* [PATCH 00/21] BlueZ 5.0 patches
@ 2012-06-13 20:43 Gustavo Padovan
2012-06-13 20:43 ` [PATCH 02/21] remove the hciops plugin Gustavo Padovan
` (19 more replies)
0 siblings, 20 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
BlueZ 4.100 was just tagged in git so let's start the work towards the
BlueZ 5.0 release.
Gustavo Padovan (21):
remove compat daemons
remove the hciops plugin
headset: remove deprecated DBus methods
sink: remove deprecated DBus method
adapter: remove deprecated ListDevices() method
manager: remove deprecated ListAdapters() method
adapter: remove btd_adapter_encrypt_link()
adapter_ops: remove disable_cod_cache
manager: remove unused manager_add_adapter()
adapter: make restore powered work again
serial: remove SerialProxy interface
serial: remove unneeded headers include
input: remove unneeded header inclusions
serial: remove old way to connect to a serial port
emulator: move it to the tools folder
btmgmt: move to tools folder
alert: move alert to profiles dir
deviceinfo: move to profiles folder
proximity: move to the profiles folder
thermometer: move to the profiles folder
time: move to the profiles folder
.gitignore | 4 +-
Makefile.am | 45 +-
Makefile.tools | 55 +-
acinclude.m4 | 18 -
alert/main.c | 58 -
alert/server.c | 38 -
alert/server.h | 26 -
audio/headset.c | 151 --
audio/sink.c | 24 -
bootstrap-configure | 3 -
compat/bnep.c | 339 ----
compat/dun.c | 334 ---
compat/dund.1 | 72 -
compat/dund.c | 645 ------
compat/dund.h | 40 -
compat/fakehid.c | 669 ------
compat/fakehid.txt | 134 --
compat/hidd.1 | 41 -
compat/hidd.c | 848 --------
compat/hidd.h | 30 -
compat/lib.h | 86 -
compat/msdun.c | 153 --
compat/pand.1 | 77 -
compat/pand.c | 811 --------
compat/pand.h | 36 -
compat/sdp.c | 706 -------
compat/sdp.h | 39 -
deviceinfo/deviceinfo.c | 192 --
deviceinfo/deviceinfo.h | 24 -
deviceinfo/main.c | 52 -
deviceinfo/manager.c | 80 -
deviceinfo/manager.h | 24 -
doc/adapter-api.txt | 10 -
doc/audio-api.txt | 33 -
doc/serial-api.txt | 138 +-
emulator/btdev.c | 1076 ----------
emulator/btdev.h | 38 -
emulator/main.c | 73 -
emulator/server.c | 288 ---
emulator/server.h | 30 -
emulator/vhci.c | 133 --
emulator/vhci.h | 35 -
input/device.c | 43 +-
input/fakehid.c | 4 -
input/manager.c | 3 -
mgmt/main.c | 1933 ------------------
plugins/hciops.c | 3943 ------------------------------------
plugins/mgmtops.c | 28 -
profiles/alert/main.c | 58 +
profiles/alert/server.c | 38 +
profiles/alert/server.h | 26 +
profiles/deviceinfo/deviceinfo.c | 192 ++
profiles/deviceinfo/deviceinfo.h | 24 +
profiles/deviceinfo/main.c | 52 +
profiles/deviceinfo/manager.c | 80 +
profiles/deviceinfo/manager.h | 24 +
profiles/proximity/immalert.c | 290 +++
profiles/proximity/immalert.h | 26 +
profiles/proximity/linkloss.c | 338 ++++
profiles/proximity/linkloss.h | 26 +
profiles/proximity/main.c | 96 +
profiles/proximity/manager.c | 150 ++
profiles/proximity/manager.h | 26 +
profiles/proximity/monitor.c | 667 ++++++
profiles/proximity/monitor.h | 34 +
profiles/proximity/proximity.conf | 9 +
profiles/proximity/reporter.c | 306 +++
profiles/proximity/reporter.h | 42 +
profiles/thermometer/main.c | 70 +
profiles/thermometer/manager.c | 92 +
profiles/thermometer/manager.h | 24 +
profiles/thermometer/thermometer.c | 1265 ++++++++++++
profiles/thermometer/thermometer.h | 25 +
profiles/time/main.c | 58 +
profiles/time/server.c | 154 ++
profiles/time/server.h | 26 +
proximity/immalert.c | 290 ---
proximity/immalert.h | 26 -
proximity/linkloss.c | 338 ----
proximity/linkloss.h | 26 -
proximity/main.c | 96 -
proximity/manager.c | 150 --
proximity/manager.h | 26 -
proximity/monitor.c | 667 ------
proximity/monitor.h | 34 -
proximity/proximity.conf | 9 -
proximity/reporter.c | 306 ---
proximity/reporter.h | 42 -
serial/manager.c | 47 -
serial/port.c | 210 +-
serial/proxy.c | 1269 ------------
serial/proxy.h | 25 -
src/adapter.c | 48 +-
src/adapter.h | 7 -
src/manager.c | 45 -
src/manager.h | 1 -
thermometer/main.c | 70 -
thermometer/manager.c | 92 -
thermometer/manager.h | 24 -
thermometer/thermometer.c | 1265 ------------
thermometer/thermometer.h | 25 -
time/main.c | 58 -
time/server.c | 154 --
time/server.h | 26 -
tools/emulator/btdev.c | 1076 ++++++++++
tools/emulator/btdev.h | 38 +
tools/emulator/main.c | 73 +
tools/emulator/server.c | 288 +++
tools/emulator/server.h | 30 +
tools/emulator/vhci.c | 133 ++
tools/emulator/vhci.h | 35 +
tools/mgmt/main.c | 1933 ++++++++++++++++++
112 files changed, 7884 insertions(+), 18978 deletions(-)
delete mode 100644 alert/main.c
delete mode 100644 alert/server.c
delete mode 100644 alert/server.h
delete mode 100644 compat/bnep.c
delete mode 100644 compat/dun.c
delete mode 100644 compat/dund.1
delete mode 100644 compat/dund.c
delete mode 100644 compat/dund.h
delete mode 100644 compat/fakehid.c
delete mode 100644 compat/fakehid.txt
delete mode 100644 compat/hidd.1
delete mode 100644 compat/hidd.c
delete mode 100644 compat/hidd.h
delete mode 100644 compat/lib.h
delete mode 100644 compat/msdun.c
delete mode 100644 compat/pand.1
delete mode 100644 compat/pand.c
delete mode 100644 compat/pand.h
delete mode 100644 compat/sdp.c
delete mode 100644 compat/sdp.h
delete mode 100644 deviceinfo/deviceinfo.c
delete mode 100644 deviceinfo/deviceinfo.h
delete mode 100644 deviceinfo/main.c
delete mode 100644 deviceinfo/manager.c
delete mode 100644 deviceinfo/manager.h
delete mode 100644 emulator/btdev.c
delete mode 100644 emulator/btdev.h
delete mode 100644 emulator/main.c
delete mode 100644 emulator/server.c
delete mode 100644 emulator/server.h
delete mode 100644 emulator/vhci.c
delete mode 100644 emulator/vhci.h
delete mode 100644 mgmt/main.c
delete mode 100644 plugins/hciops.c
create mode 100644 profiles/alert/main.c
create mode 100644 profiles/alert/server.c
create mode 100644 profiles/alert/server.h
create mode 100644 profiles/deviceinfo/deviceinfo.c
create mode 100644 profiles/deviceinfo/deviceinfo.h
create mode 100644 profiles/deviceinfo/main.c
create mode 100644 profiles/deviceinfo/manager.c
create mode 100644 profiles/deviceinfo/manager.h
create mode 100644 profiles/proximity/immalert.c
create mode 100644 profiles/proximity/immalert.h
create mode 100644 profiles/proximity/linkloss.c
create mode 100644 profiles/proximity/linkloss.h
create mode 100644 profiles/proximity/main.c
create mode 100644 profiles/proximity/manager.c
create mode 100644 profiles/proximity/manager.h
create mode 100644 profiles/proximity/monitor.c
create mode 100644 profiles/proximity/monitor.h
create mode 100644 profiles/proximity/proximity.conf
create mode 100644 profiles/proximity/reporter.c
create mode 100644 profiles/proximity/reporter.h
create mode 100644 profiles/thermometer/main.c
create mode 100644 profiles/thermometer/manager.c
create mode 100644 profiles/thermometer/manager.h
create mode 100644 profiles/thermometer/thermometer.c
create mode 100644 profiles/thermometer/thermometer.h
create mode 100644 profiles/time/main.c
create mode 100644 profiles/time/server.c
create mode 100644 profiles/time/server.h
delete mode 100644 proximity/immalert.c
delete mode 100644 proximity/immalert.h
delete mode 100644 proximity/linkloss.c
delete mode 100644 proximity/linkloss.h
delete mode 100644 proximity/main.c
delete mode 100644 proximity/manager.c
delete mode 100644 proximity/manager.h
delete mode 100644 proximity/monitor.c
delete mode 100644 proximity/monitor.h
delete mode 100644 proximity/proximity.conf
delete mode 100644 proximity/reporter.c
delete mode 100644 proximity/reporter.h
delete mode 100644 serial/proxy.c
delete mode 100644 serial/proxy.h
delete mode 100644 thermometer/main.c
delete mode 100644 thermometer/manager.c
delete mode 100644 thermometer/manager.h
delete mode 100644 thermometer/thermometer.c
delete mode 100644 thermometer/thermometer.h
delete mode 100644 time/main.c
delete mode 100644 time/server.c
delete mode 100644 time/server.h
create mode 100644 tools/emulator/btdev.c
create mode 100644 tools/emulator/btdev.h
create mode 100644 tools/emulator/main.c
create mode 100644 tools/emulator/server.c
create mode 100644 tools/emulator/server.h
create mode 100644 tools/emulator/vhci.c
create mode 100644 tools/emulator/vhci.h
create mode 100644 tools/mgmt/main.c
--
1.7.10.2
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 02/21] remove the hciops plugin
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 03/21] headset: remove deprecated DBus methods Gustavo Padovan
` (18 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
hciops was replaced by mgmtops, it should not be maintained anymore and is
now removed.
---
Makefile.am | 4 +-
plugins/hciops.c | 3943 ------------------------------------------------------
2 files changed, 2 insertions(+), 3945 deletions(-)
delete mode 100644 plugins/hciops.c
diff --git a/Makefile.am b/Makefile.am
index 53fcbe9..8c9ff3a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -238,8 +238,8 @@ builtin_sources += thermometer/main.c \
endif
-builtin_modules += hciops mgmtops
-builtin_sources += plugins/hciops.c plugins/mgmtops.c
+builtin_modules += mgmtops
+builtin_sources += plugins/mgmtops.c
if HAL
builtin_modules += hal
diff --git a/plugins/hciops.c b/plugins/hciops.c
deleted file mode 100644
index d74f2ea..0000000
--- a/plugins/hciops.c
+++ /dev/null
@@ -1,3943 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- * 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 <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-
-#include "hcid.h"
-#include "sdpd.h"
-#include "btio.h"
-#include "adapter.h"
-#include "device.h"
-#include "plugin.h"
-#include "log.h"
-#include "storage.h"
-#include "event.h"
-#include "manager.h"
-#include "oob.h"
-#include "eir.h"
-
-#define DISCOV_HALTED 0
-#define DISCOV_INQ 1
-#define DISCOV_SCAN 2
-#define DISCOV_NAMES 3
-
-#define TIMEOUT_BR_LE_SCAN 5120 /* TGAP(100)/2 */
-#define TIMEOUT_LE_SCAN 10240 /* TGAP(gen_disc_scan_min) */
-
-#define LENGTH_BR_INQ 0x08
-#define LENGTH_BR_LE_INQ 0x04
-
-static int start_scanning(int index, int timeout);
-
-static int child_pipe[2] = { -1, -1 };
-
-static guint child_io_id = 0;
-static guint ctl_io_id = 0;
-
-enum adapter_type {
- BR_EDR,
- LE_ONLY,
- BR_EDR_LE,
- UNKNOWN,
-};
-
-/* Commands sent by kernel on starting an adapter */
-enum {
- PENDING_BDADDR,
- PENDING_VERSION,
- PENDING_FEATURES,
- PENDING_NAME,
-};
-
-struct bt_conn {
- struct dev_info *dev;
- bdaddr_t bdaddr;
- uint16_t handle;
- uint8_t loc_cap;
- uint8_t loc_auth;
- uint8_t rem_cap;
- uint8_t rem_auth;
- uint8_t rem_oob_data;
- gboolean bonding_initiator;
- gboolean secmode3;
- GIOChannel *io; /* For raw L2CAP socket (bonding) */
-};
-
-struct oob_data {
- bdaddr_t bdaddr;
- uint8_t hash[16];
- uint8_t randomizer[16];
-};
-
-enum name_state {
- NAME_UNKNOWN,
- NAME_NEEDED,
- NAME_NOT_NEEDED,
- NAME_PENDING,
-};
-
-struct found_dev {
- bdaddr_t bdaddr;
- int8_t rssi;
- enum name_state name_state;
-};
-
-static int max_dev = -1;
-static struct dev_info {
- int id;
- int sk;
- bdaddr_t bdaddr;
- char name[249];
- uint8_t eir[HCI_MAX_EIR_LENGTH];
- uint8_t features[8];
- uint8_t extfeatures[8];
- uint8_t ssp_mode;
-
- int8_t tx_power;
-
- int discov_state;
-
- uint32_t current_cod;
- uint32_t wanted_cod;
- uint32_t pending_cod;
- gboolean cache_enable;
- gboolean already_up;
- gboolean registered;
- gboolean pairable;
-
- uint8_t io_capability;
-
- struct hci_version ver;
-
- uint16_t did_source;
- uint16_t did_vendor;
- uint16_t did_product;
- uint16_t did_version;
-
- gboolean up;
- uint32_t pending;
-
- GIOChannel *io;
- guint watch_id;
-
- gboolean debug_keys;
- GSList *keys;
- uint8_t pin_length;
-
- GSList *oob_data;
-
- GSList *uuids;
-
- GSList *connections;
-
- GSList *found_devs;
- GSList *need_name;
-
- guint stop_scan_id;
-
- uint16_t discoverable_timeout;
- guint discoverable_id;
-} *devs = NULL;
-
-static int found_dev_rssi_cmp(gconstpointer a, gconstpointer b)
-{
- const struct found_dev *d1 = a, *d2 = b;
- int rssi1, rssi2;
-
- if (d2->name_state == NAME_NOT_NEEDED)
- return -1;
-
- rssi1 = d1->rssi < 0 ? -d1->rssi : d1->rssi;
- rssi2 = d2->rssi < 0 ? -d2->rssi : d2->rssi;
-
- return rssi1 - rssi2;
-}
-
-static int found_dev_bda_cmp(gconstpointer a, gconstpointer b)
-{
- const struct found_dev *d1 = a, *d2 = b;
-
- return bacmp(&d1->bdaddr, &d2->bdaddr);
-}
-
-static void found_dev_cleanup(struct dev_info *info)
-{
- g_slist_free_full(info->found_devs, g_free);
- info->found_devs = NULL;
-
- g_slist_free_full(info->need_name, g_free);
- info->need_name = NULL;
-}
-
-static int resolve_name(struct dev_info *info, bdaddr_t *bdaddr)
-{
- remote_name_req_cp cp;
- char addr[18];
-
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s", info->id, addr);
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, bdaddr);
- cp.pscan_rep_mode = 0x02;
-
- if (hci_send_cmd(info->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ,
- REMOTE_NAME_REQ_CP_SIZE, &cp) < 0)
- return -errno;
-
- return 0;
-}
-
-static int resolve_names(struct dev_info *info, struct btd_adapter *adapter)
-{
- struct found_dev *dev;
-
- DBG("found_dev %u need_name %u", g_slist_length(info->found_devs),
- g_slist_length(info->need_name));
-
- if (g_slist_length(info->need_name) == 0)
- return -ENOENT;
-
- dev = info->need_name->data;
- resolve_name(info, &dev->bdaddr);
- dev->name_state = NAME_PENDING;
-
- return 0;
-}
-
-static void set_state(int index, int state)
-{
- struct btd_adapter *adapter;
- struct dev_info *dev = &devs[index];
-
- if (dev->discov_state == state)
- return;
-
- adapter = manager_find_adapter_by_id(index);
- if (!adapter) {
- error("No matching adapter found");
- return;
- }
-
- dev->discov_state = state;
-
- DBG("hci%d: new state %d", index, dev->discov_state);
-
- switch (dev->discov_state) {
- case DISCOV_HALTED:
- found_dev_cleanup(dev);
- adapter_set_discovering(adapter, FALSE);
- break;
- case DISCOV_INQ:
- case DISCOV_SCAN:
- adapter_set_discovering(adapter, TRUE);
- break;
- case DISCOV_NAMES:
- if (resolve_names(dev, adapter) < 0)
- set_state(index, DISCOV_HALTED);
- break;
- }
-}
-
-static inline gboolean is_le_capable(int index)
-{
- struct dev_info *dev = &devs[index];
-
- return (dev->features[4] & LMP_LE &&
- dev->extfeatures[0] & LMP_HOST_LE) ? TRUE : FALSE;
-}
-
-static inline gboolean is_bredr_capable(int index)
-{
- struct dev_info *dev = &devs[index];
-
- return (dev->features[4] & LMP_NO_BREDR) == 0 ? TRUE : FALSE;
-}
-
-static int get_adapter_type(int index)
-{
- if (is_le_capable(index) && is_bredr_capable(index))
- return BR_EDR_LE;
- else if (is_le_capable(index))
- return LE_ONLY;
- else if (is_bredr_capable(index))
- return BR_EDR;
-
- return UNKNOWN;
-}
-
-static int ignore_device(struct hci_dev_info *di)
-{
- return hci_test_bit(HCI_RAW, &di->flags) || di->type >> 4 != HCI_BREDR;
-}
-
-static struct dev_info *init_dev_info(int index, int sk, gboolean registered,
- gboolean already_up)
-{
- struct dev_info *dev = &devs[index];
-
- memset(dev, 0, sizeof(*dev));
-
- dev->id = index;
- dev->sk = sk;
- dev->cache_enable = TRUE;
- dev->registered = registered;
- dev->already_up = already_up;
- dev->io_capability = 0x03; /* No Input No Output */
- dev->discov_state = DISCOV_HALTED;
-
- return dev;
-}
-
-/* Async HCI command handling with callback support */
-
-struct hci_cmd_data {
- bt_hci_result_t cb;
- uint16_t handle;
- uint16_t ocf;
- gpointer caller_data;
-};
-
-static gboolean hci_event_watch(GIOChannel *io,
- GIOCondition cond, gpointer user_data)
-{
- unsigned char buf[HCI_MAX_EVENT_SIZE], *body;
- struct hci_cmd_data *cmd = user_data;
- evt_cmd_status *evt_status;
- evt_auth_complete *evt_auth;
- evt_encrypt_change *evt_enc;
- hci_event_hdr *hdr;
- set_conn_encrypt_cp cp;
- int dd;
- uint16_t ocf;
- uint8_t status = HCI_OE_POWER_OFF;
-
- if (cond & G_IO_NVAL) {
- cmd->cb(status, cmd->caller_data);
- return FALSE;
- }
-
- if (cond & (G_IO_ERR | G_IO_HUP))
- goto failed;
-
- dd = g_io_channel_unix_get_fd(io);
-
- if (read(dd, buf, sizeof(buf)) < 0)
- goto failed;
-
- hdr = (hci_event_hdr *) (buf + 1);
- body = buf + (1 + HCI_EVENT_HDR_SIZE);
-
- switch (hdr->evt) {
- case EVT_CMD_STATUS:
- evt_status = (evt_cmd_status *) body;
- ocf = cmd_opcode_ocf(evt_status->opcode);
- if (ocf != cmd->ocf)
- return TRUE;
- switch (ocf) {
- case OCF_AUTH_REQUESTED:
- case OCF_SET_CONN_ENCRYPT:
- if (evt_status->status != 0) {
- /* Baseband rejected command */
- status = evt_status->status;
- goto failed;
- }
- break;
- default:
- return TRUE;
- }
- /* Wait for the next event */
- return TRUE;
- case EVT_AUTH_COMPLETE:
- evt_auth = (evt_auth_complete *) body;
- if (evt_auth->handle != cmd->handle) {
- /* Skipping */
- return TRUE;
- }
-
- if (evt_auth->status != 0x00) {
- status = evt_auth->status;
- /* Abort encryption */
- goto failed;
- }
-
- memset(&cp, 0, sizeof(cp));
- cp.handle = cmd->handle;
- cp.encrypt = 1;
-
- cmd->ocf = OCF_SET_CONN_ENCRYPT;
-
- if (hci_send_cmd(dd, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
- SET_CONN_ENCRYPT_CP_SIZE, &cp) < 0) {
- status = HCI_COMMAND_DISALLOWED;
- goto failed;
- }
- /* Wait for encrypt change event */
- return TRUE;
- case EVT_ENCRYPT_CHANGE:
- evt_enc = (evt_encrypt_change *) body;
- if (evt_enc->handle != cmd->handle)
- return TRUE;
-
- /* Procedure finished: reporting status */
- status = evt_enc->status;
- break;
- default:
- /* Skipping */
- return TRUE;
- }
-
-failed:
- cmd->cb(status, cmd->caller_data);
- g_io_channel_shutdown(io, TRUE, NULL);
-
- return FALSE;
-}
-
-static int write_inq_mode(int index, uint8_t mode)
-{
- struct dev_info *dev = &devs[index];
- write_inquiry_mode_cp cp;
-
- memset(&cp, 0, sizeof(cp));
- cp.mode = mode;
-
- if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE,
- WRITE_INQUIRY_MODE_CP_SIZE, &cp) < 0)
- return -errno;
-
- return 0;
-}
-
-static uint8_t get_inquiry_mode(int index)
-{
- struct dev_info *dev = &devs[index];
-
- if (dev->features[6] & LMP_EXT_INQ)
- return 2;
-
- if (dev->features[3] & LMP_RSSI_INQ)
- return 1;
-
- if (dev->ver.manufacturer == 11 && dev->ver.hci_rev == 0x00 &&
- dev->ver.lmp_subver == 0x0757)
- return 1;
-
- if (dev->ver.manufacturer == 15) {
- if (dev->ver.hci_rev == 0x03 &&
- dev->ver.lmp_subver == 0x6963)
- return 1;
- if (dev->ver.hci_rev == 0x09 &&
- dev->ver.lmp_subver == 0x6963)
- return 1;
- if (dev->ver.hci_rev == 0x00 &&
- dev->ver.lmp_subver == 0x6965)
- return 1;
- }
-
- if (dev->ver.manufacturer == 31 && dev->ver.hci_rev == 0x2005 &&
- dev->ver.lmp_subver == 0x1805)
- return 1;
-
- return 0;
-}
-
-static int init_ssp_mode(int index)
-{
- struct dev_info *dev = &devs[index];
- write_simple_pairing_mode_cp cp;
-
- if (ioctl(dev->sk, HCIGETAUTHINFO, NULL) < 0 && errno == EINVAL)
- return 0;
-
- memset(&cp, 0, sizeof(cp));
- cp.mode = 0x01;
-
- if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
- OCF_WRITE_SIMPLE_PAIRING_MODE,
- WRITE_SIMPLE_PAIRING_MODE_CP_SIZE, &cp) < 0)
- return -errno;
-
- return 0;
-}
-
-static int hciops_set_discoverable(int index, gboolean discoverable,
- uint16_t timeout)
-{
- struct dev_info *dev = &devs[index];
- uint8_t mode;
-
- if (discoverable)
- mode = (SCAN_PAGE | SCAN_INQUIRY);
- else
- mode = SCAN_PAGE;
-
- DBG("hci%d discoverable %d", index, discoverable);
-
- if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
- 1, &mode) < 0)
- return -errno;
-
- dev->discoverable_timeout = timeout;
-
- return 0;
-}
-
-static int hciops_set_pairable(int index, gboolean pairable)
-{
- struct btd_adapter *adapter;
-
- DBG("hci%d pairable %d", index, pairable);
-
- adapter = manager_find_adapter(&devs[index].bdaddr);
- if (adapter)
- btd_adapter_pairable_changed(adapter, pairable);
-
- devs[index].pairable = pairable;
-
- return 0;
-}
-
-static int hciops_power_off(int index)
-{
- struct dev_info *dev = &devs[index];
-
- DBG("hci%d", index);
-
- if (ioctl(dev->sk, HCIDEVDOWN, index) < 0 && errno != EALREADY)
- return -errno;
-
- return 0;
-}
-
-static void set_event_mask(int index)
-{
- struct dev_info *dev = &devs[index];
- /* The second byte is 0xff instead of 0x9f (two reserved bits
- * disabled) since a Broadcom 1.2 dongle doesn't respond to the
- * command otherwise */
- uint8_t events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
-
- /* Events for 1.2 and newer controllers */
- if (dev->ver.lmp_ver > 1) {
- events[4] |= 0x01; /* Flow Specification Complete */
- events[4] |= 0x02; /* Inquiry Result with RSSI */
- events[4] |= 0x04; /* Read Remote Extended Features Complete */
- events[5] |= 0x08; /* Synchronous Connection Complete */
- events[5] |= 0x10; /* Synchronous Connection Changed */
- }
-
- if (dev->features[3] & LMP_RSSI_INQ)
- events[4] |= 0x02; /* Inquiry Result with RSSI */
-
- if (dev->features[5] & LMP_SNIFF_SUBR)
- events[5] |= 0x20; /* Sniff Subrating */
-
- if (dev->features[5] & LMP_PAUSE_ENC)
- events[5] |= 0x80; /* Encryption Key Refresh Complete */
-
- if (dev->features[6] & LMP_EXT_INQ)
- events[5] |= 0x40; /* Extended Inquiry Result */
-
- if (dev->features[6] & LMP_NFLUSH_PKTS)
- events[7] |= 0x01; /* Enhanced Flush Complete */
-
- if (dev->features[7] & LMP_LSTO)
- events[6] |= 0x80; /* Link Supervision Timeout Changed */
-
- if (dev->features[6] & LMP_SIMPLE_PAIR) {
- events[6] |= 0x01; /* IO Capability Request */
- events[6] |= 0x02; /* IO Capability Response */
- events[6] |= 0x04; /* User Confirmation Request */
- events[6] |= 0x08; /* User Passkey Request */
- events[6] |= 0x10; /* Remote OOB Data Request */
- events[6] |= 0x20; /* Simple Pairing Complete */
- events[7] |= 0x04; /* User Passkey Notification */
- events[7] |= 0x08; /* Keypress Notification */
- events[7] |= 0x10; /* Remote Host Supported
- * Features Notification */
- }
-
- if (dev->features[4] & LMP_LE)
- events[7] |= 0x20; /* LE Meta-Event */
-
- hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_SET_EVENT_MASK,
- sizeof(events), events);
-}
-
-static void start_adapter(int index)
-{
- struct dev_info *dev = &devs[index];
- uint8_t inqmode;
- uint16_t link_policy;
-
- set_event_mask(index);
-
- if (dev->features[6] & LMP_SIMPLE_PAIR)
- init_ssp_mode(index);
-
- inqmode = get_inquiry_mode(index);
- if (inqmode)
- write_inq_mode(index, inqmode);
-
- if (dev->features[7] & LMP_INQ_TX_PWR)
- hci_send_cmd(dev->sk, OGF_HOST_CTL,
- OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, 0, NULL);
-
- /* Set default link policy */
- link_policy = main_opts.link_policy;
-
- if (!(dev->features[0] & LMP_RSWITCH))
- link_policy &= ~HCI_LP_RSWITCH;
- if (!(dev->features[0] & LMP_HOLD))
- link_policy &= ~HCI_LP_HOLD;
- if (!(dev->features[0] & LMP_SNIFF))
- link_policy &= ~HCI_LP_SNIFF;
- if (!(dev->features[1] & LMP_PARK))
- link_policy &= ~HCI_LP_PARK;
-
- link_policy = htobs(link_policy);
- hci_send_cmd(dev->sk, OGF_LINK_POLICY, OCF_WRITE_DEFAULT_LINK_POLICY,
- sizeof(link_policy), &link_policy);
-
- dev->current_cod = 0;
- memset(dev->eir, 0, sizeof(dev->eir));
-}
-
-static int hciops_stop_inquiry(int index)
-{
- struct dev_info *dev = &devs[index];
-
- DBG("hci%d", index);
-
- if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_INQUIRY_CANCEL, 0, 0) < 0)
- return -errno;
-
- return 0;
-}
-
-static void update_ext_inquiry_response(int index)
-{
- struct dev_info *dev = &devs[index];
- write_ext_inquiry_response_cp cp;
-
- DBG("hci%d", index);
-
- if (!(dev->features[6] & LMP_EXT_INQ))
- return;
-
- if (dev->ssp_mode == 0)
- return;
-
- if (dev->cache_enable)
- return;
-
- memset(&cp, 0, sizeof(cp));
-
- eir_create(dev->name, dev->tx_power, dev->did_vendor, dev->did_product,
- dev->did_version, dev->did_source, dev->uuids,
- cp.data);
-
- if (memcmp(cp.data, dev->eir, sizeof(cp.data)) == 0)
- return;
-
- memcpy(dev->eir, cp.data, sizeof(cp.data));
-
- if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
- OCF_WRITE_EXT_INQUIRY_RESPONSE,
- WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE, &cp) < 0)
- error("Unable to write EIR data: %s (%d)",
- strerror(errno), errno);
-}
-
-static int hciops_set_name(int index, const char *name)
-{
- struct dev_info *dev = &devs[index];
- change_local_name_cp cp;
-
- DBG("hci%d, name %s", index, name);
-
- memset(&cp, 0, sizeof(cp));
- strncpy((char *) cp.name, name, sizeof(cp.name));
-
- if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME,
- CHANGE_LOCAL_NAME_CP_SIZE, &cp) < 0)
- return -errno;
-
- memcpy(dev->name, cp.name, 248);
- update_ext_inquiry_response(index);
-
- return 0;
-}
-
-static int write_class(int index, uint32_t class)
-{
- struct dev_info *dev = &devs[index];
- write_class_of_dev_cp cp;
-
- DBG("hci%d class 0x%06x", index, class);
-
- memcpy(cp.dev_class, &class, 3);
-
- if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
- WRITE_CLASS_OF_DEV_CP_SIZE, &cp) < 0)
- return -errno;
-
- dev->pending_cod = class;
-
- return 0;
-}
-
-static int hciops_set_dev_class(int index, uint8_t major, uint8_t minor)
-{
- struct dev_info *dev = &devs[index];
- int err;
-
- DBG("hci%d major %u minor %u", index, major, minor);
-
- /* Update only the major and minor class bits keeping remaining bits
- * intact*/
- dev->wanted_cod &= 0xffe000;
- dev->wanted_cod |= ((major & 0x1f) << 8) | minor;
-
- if (dev->wanted_cod == dev->current_cod ||
- dev->cache_enable || dev->pending_cod)
- return 0;
-
- DBG("Changing Major/Minor class to 0x%06x", dev->wanted_cod);
-
- err = write_class(index, dev->wanted_cod);
- if (err < 0)
- error("Adapter class update failed: %s (%d)",
- strerror(-err), -err);
-
- return err;
-}
-
-static gboolean init_adapter(int index)
-{
- struct dev_info *dev = &devs[index];
- struct btd_adapter *adapter = NULL;
- gboolean existing_adapter = dev->registered;
- uint8_t mode, on_mode, major, minor;
- gboolean pairable, discoverable;
- const char *name;
- uint16_t discoverable_timeout;
-
- if (!dev->registered) {
- adapter = btd_manager_register_adapter(index, TRUE);
- if (adapter)
- dev->registered = TRUE;
- } else {
- adapter = manager_find_adapter(&dev->bdaddr);
- /* FIXME: manager_find_adapter should return a new ref */
- btd_adapter_ref(adapter);
- }
-
- if (adapter == NULL)
- return FALSE;
-
- btd_adapter_get_mode(adapter, &mode, &on_mode,
- &discoverable_timeout,
- &pairable);
-
- if (existing_adapter)
- mode = on_mode;
-
- if (mode == MODE_OFF) {
- hciops_power_off(index);
- goto done;
- }
-
- start_adapter(index);
-
- name = btd_adapter_get_name(adapter);
- if (name)
- hciops_set_name(index, name);
-
- btd_adapter_get_class(adapter, &major, &minor);
- hciops_set_dev_class(index, major, minor);
-
- btd_adapter_start(adapter);
-
- discoverable = (mode == MODE_DISCOVERABLE);
-
- hciops_set_discoverable(index, discoverable, discoverable_timeout);
- hciops_set_pairable(index, pairable);
-
- if (dev->already_up)
- hciops_stop_inquiry(index);
-
-done:
- btd_adapter_unref(adapter);
- return TRUE;
-}
-
-static int hciops_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
- gpointer user_data)
-{
- GIOChannel *io;
- struct hci_cmd_data *cmd;
- struct hci_conn_info_req *cr;
- auth_requested_cp cp;
- struct hci_filter nf;
- int dd, err;
- uint32_t link_mode;
- uint16_t handle;
-
- dd = hci_open_dev(index);
- if (dd < 0)
- return -errno;
-
- cr = g_malloc0(sizeof(*cr) + sizeof(struct hci_conn_info));
- cr->type = ACL_LINK;
- bacpy(&cr->bdaddr, dst);
-
- err = ioctl(dd, HCIGETCONNINFO, cr);
- link_mode = cr->conn_info->link_mode;
- handle = cr->conn_info->handle;
- g_free(cr);
-
- if (err < 0) {
- err = -errno;
- goto fail;
- }
-
- if (link_mode & HCI_LM_ENCRYPT) {
- err = -EALREADY;
- goto fail;
- }
-
- memset(&cp, 0, sizeof(cp));
- cp.handle = htobs(handle);
-
- if (hci_send_cmd(dd, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
- AUTH_REQUESTED_CP_SIZE, &cp) < 0) {
- err = -errno;
- goto fail;
- }
-
- cmd = g_new0(struct hci_cmd_data, 1);
- cmd->handle = handle;
- cmd->ocf = OCF_AUTH_REQUESTED;
- cmd->cb = cb;
- cmd->caller_data = user_data;
-
- hci_filter_clear(&nf);
- hci_filter_set_ptype(HCI_EVENT_PKT, &nf);
- hci_filter_set_event(EVT_CMD_STATUS, &nf);
- hci_filter_set_event(EVT_AUTH_COMPLETE, &nf);
- hci_filter_set_event(EVT_ENCRYPT_CHANGE, &nf);
-
- if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) {
- err = -errno;
- g_free(cmd);
- goto fail;
- }
-
- io = g_io_channel_unix_new(dd);
- g_io_channel_set_close_on_unref(io, FALSE);
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
- G_IO_HUP | G_IO_ERR | G_IO_NVAL | G_IO_IN,
- hci_event_watch, cmd, g_free);
- g_io_channel_unref(io);
-
- return 0;
-
-fail:
- close(dd);
- return err;
-}
-
-static int hciops_set_did(int index, uint16_t vendor, uint16_t product,
- uint16_t version, uint16_t source)
-{
- struct dev_info *dev = &devs[index];
-
- dev->did_vendor = vendor;
- dev->did_product = product;
- dev->did_version = version;
- dev->did_source = source;
-
- return 0;
-}
-
-/* End async HCI command handling */
-
-/* Start of HCI event callbacks */
-
-static gint conn_handle_cmp(gconstpointer a, gconstpointer b)
-{
- const struct bt_conn *conn = a;
- uint16_t handle = *((const uint16_t *) b);
-
- return (int) conn->handle - (int) handle;
-}
-
-static struct bt_conn *find_conn_by_handle(struct dev_info *dev,
- uint16_t handle)
-{
- GSList *match;
-
- match = g_slist_find_custom(dev->connections, &handle,
- conn_handle_cmp);
- if (match)
- return match->data;
-
- return NULL;
-}
-
-static gint conn_bdaddr_cmp(gconstpointer a, gconstpointer b)
-{
- const struct bt_conn *conn = a;
- const bdaddr_t *bdaddr = b;
-
- return bacmp(&conn->bdaddr, bdaddr);
-}
-
-static struct bt_conn *find_connection(struct dev_info *dev, bdaddr_t *bdaddr)
-{
- GSList *match;
-
- match = g_slist_find_custom(dev->connections, bdaddr, conn_bdaddr_cmp);
- if (match)
- return match->data;
-
- return NULL;
-}
-
-static struct bt_conn *get_connection(struct dev_info *dev, bdaddr_t *bdaddr)
-{
- struct bt_conn *conn;
-
- conn = find_connection(dev, bdaddr);
- if (conn)
- return conn;
-
- conn = g_new0(struct bt_conn, 1);
-
- conn->dev = dev;
- conn->loc_cap = dev->io_capability;
- conn->loc_auth = 0xff;
- conn->rem_auth = 0xff;
- bacpy(&conn->bdaddr, bdaddr);
-
- dev->connections = g_slist_append(dev->connections, conn);
-
- return conn;
-}
-
-static int get_handle(int index, bdaddr_t *bdaddr, uint16_t *handle)
-{
- struct dev_info *dev = &devs[index];
- struct bt_conn *conn;
- char addr[18];
-
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s", index, addr);
-
- conn = find_connection(dev, bdaddr);
- if (conn == NULL)
- return -ENOENT;
-
- *handle = conn->handle;
-
- return 0;
-}
-
-static int disconnect_addr(int index, bdaddr_t *dba, uint8_t reason)
-{
- disconnect_cp cp;
- uint16_t handle;
- int err;
-
- err = get_handle(index, dba, &handle);
- if (err < 0)
- return err;
-
- memset(&cp, 0, sizeof(cp));
- cp.handle = htobs(handle);
- cp.reason = reason;
-
- if (hci_send_cmd(devs[index].sk, OGF_LINK_CTL, OCF_DISCONNECT,
- DISCONNECT_CP_SIZE, &cp) < 0)
- return -errno;
-
- return 0;
-}
-
-static void bonding_complete(struct dev_info *dev, struct bt_conn *conn,
- uint8_t status)
-{
- struct btd_adapter *adapter;
-
- DBG("status 0x%02x", status);
-
- if (conn->io != NULL) {
- /* bonding_connect_cb takes care of the successul case */
- if (status != 0)
- g_io_channel_shutdown(conn->io, TRUE, NULL);
- g_io_channel_unref(conn->io);
- conn->io = NULL;
- }
-
- conn->bonding_initiator = FALSE;
-
- adapter = manager_find_adapter(&dev->bdaddr);
- if (adapter)
- adapter_bonding_complete(adapter, &conn->bdaddr, status);
-}
-
-static int get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth)
-{
- struct dev_info *dev = &devs[index];
- struct hci_auth_info_req req;
- char addr[18];
-
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s", index, addr);
-
- memset(&req, 0, sizeof(req));
- bacpy(&req.bdaddr, bdaddr);
-
- if (ioctl(dev->sk, HCIGETAUTHINFO, (unsigned long) &req) < 0)
- return -errno;
-
- if (auth)
- *auth = req.type;
-
- return 0;
-}
-
-/* Link Key handling */
-
-static void link_key_request(int index, bdaddr_t *dba)
-{
- struct dev_info *dev = &devs[index];
- struct link_key_info *key_info;
- struct bt_conn *conn;
- GSList *match;
- char da[18];
-
- ba2str(dba, da);
- DBG("hci%d dba %s", index, da);
-
- conn = get_connection(dev, dba);
- if (conn->handle == 0)
- conn->secmode3 = TRUE;
-
- get_auth_info(index, dba, &conn->loc_auth);
-
- DBG("kernel auth requirements = 0x%02x", conn->loc_auth);
-
- match = g_slist_find_custom(dev->keys, dba, (GCompareFunc) bacmp);
- if (match)
- key_info = match->data;
- else
- key_info = NULL;
-
- DBG("Matching key %s", key_info ? "found" : "not found");
-
- if (key_info == NULL || (!dev->debug_keys && key_info->type == 0x03)) {
- /* Link key not found */
- hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY,
- 6, dba);
- return;
- }
-
- /* Link key found */
-
- DBG("link key type 0x%02x", key_info->type);
-
- /* Don't use unauthenticated combination keys if MITM is
- * required */
- if (key_info->type == 0x04 && conn->loc_auth != 0xff &&
- (conn->loc_auth & 0x01))
- hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY,
- 6, dba);
- else {
- link_key_reply_cp lr;
-
- memcpy(lr.link_key, key_info->key, 16);
- bacpy(&lr.bdaddr, dba);
-
- hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_LINK_KEY_REPLY,
- LINK_KEY_REPLY_CP_SIZE, &lr);
- }
-}
-
-static void link_key_notify(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_link_key_notify *evt = ptr;
- bdaddr_t *dba = &evt->bdaddr;
- struct link_key_info *key_info;
- uint8_t old_key_type, key_type;
- struct bt_conn *conn;
- GSList *match;
- char da[18];
- uint8_t status = 0;
-
- ba2str(dba, da);
- DBG("hci%d dba %s type %d", index, da, evt->key_type);
-
- conn = get_connection(dev, &evt->bdaddr);
-
- match = g_slist_find_custom(dev->keys, dba, (GCompareFunc) bacmp);
- if (match)
- key_info = match->data;
- else
- key_info = NULL;
-
- if (key_info == NULL) {
- key_info = g_new0(struct link_key_info, 1);
- bacpy(&key_info->bdaddr, &evt->bdaddr);
- old_key_type = 0xff;
- } else {
- dev->keys = g_slist_remove(dev->keys, key_info);
- old_key_type = key_info->type;
- }
-
- memcpy(key_info->key, evt->link_key, sizeof(evt->link_key));
- key_info->type = evt->key_type;
- key_info->pin_len = dev->pin_length;
-
- key_type = evt->key_type;
-
- DBG("key type 0x%02x old key type 0x%02x", key_type, old_key_type);
- DBG("local auth 0x%02x and remote auth 0x%02x",
- conn->loc_auth, conn->rem_auth);
-
- if (key_type == HCI_LK_CHANGED_COMBINATION) {
- /* Some buggy controller combinations generate a changed
- * combination key for legacy pairing even when there's no
- * previous key */
- if (conn->rem_auth == 0xff && old_key_type == 0xff)
- key_type = HCI_LK_COMBINATION;
- else if (old_key_type != 0xff)
- key_type = old_key_type;
- else
- /* This is Changed Combination Link Key for
- * a temporary link key.*/
- goto done;
- }
-
- key_info->type = key_type;
-
- /* Skip the storage check if this is a debug key */
- if (key_type == HCI_LK_DEBUG_COMBINATION)
- goto done;
-
- /* Store the link key persistently if one of the following is true:
- * 1. this is a legacy link key
- * 2. this is a changed combination key and there was a previously
- * stored one
- * 3. neither local nor remote side had no-bonding as a requirement
- * 4. the local side had dedicated bonding as a requirement
- * 5. the remote side is using dedicated bonding since in that case
- * also the local requirements are set to dedicated bonding
- * If none of the above match only keep the link key around for
- * this connection and set the temporary flag for the device.
- */
- if (key_type < HCI_LK_DEBUG_COMBINATION ||
- (key_type == HCI_LK_CHANGED_COMBINATION
- && old_key_type != HCI_LK_INVALID) ||
- (conn->loc_auth > 0x01 && conn->rem_auth > 0x01) ||
- (conn->loc_auth == 0x02 || conn->loc_auth == 0x03) ||
- (conn->rem_auth == 0x02 || conn->rem_auth == 0x03)) {
- int err;
-
- err = btd_event_link_key_notify(&dev->bdaddr, dba,
- evt->link_key, key_type,
- dev->pin_length);
-
- if (err == -ENODEV)
- status = HCI_OE_LOW_RESOURCES;
- else if (err < 0)
- status = HCI_MEMORY_FULL;
-
- goto done;
- }
-
-done:
- dev->pin_length = 0;
-
- if (status != 0) {
- g_free(key_info);
- bonding_complete(dev, conn, status);
- disconnect_addr(index, dba, status);
- return;
- }
-
- dev->keys = g_slist_prepend(dev->keys, key_info);
-
- /* If we're connected and not dedicated bonding initiators we're
- * done with the bonding process */
- if (!conn->bonding_initiator && conn->handle != 0)
- bonding_complete(dev, conn, 0);
-}
-
-static void return_link_keys(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_return_link_keys *evt = ptr;
- uint8_t num = evt->num_keys;
- unsigned char key[16];
- char da[18];
- bdaddr_t dba;
- int i;
-
- DBG("hci%d num_keys %u", index, num);
-
- ptr++;
-
- for (i = 0; i < num; i++) {
- bacpy(&dba, ptr); ba2str(&dba, da);
- memcpy(key, ptr + 6, 16);
-
- DBG("hci%d returned key for %s", index, da);
-
- btd_event_returned_link_key(&dev->bdaddr, &dba);
-
- ptr += 22;
- }
-}
-
-/* Simple Pairing handling */
-
-static int hciops_confirm_reply(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
- gboolean success)
-{
- struct dev_info *dev = &devs[index];
- user_confirm_reply_cp cp;
- char addr[18];
- int err;
-
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s success %d", index, addr, success);
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, bdaddr);
-
- if (success)
- err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
- OCF_USER_CONFIRM_REPLY,
- USER_CONFIRM_REPLY_CP_SIZE, &cp);
- else
- err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
- OCF_USER_CONFIRM_NEG_REPLY,
- USER_CONFIRM_REPLY_CP_SIZE, &cp);
-
- if (err < 0)
- err = -errno;
-
- return err;
-}
-
-static void user_confirm_request(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_user_confirm_request *req = ptr;
- gboolean loc_mitm, rem_mitm;
- struct bt_conn *conn;
-
- DBG("hci%d", index);
-
- conn = find_connection(dev, &req->bdaddr);
- if (conn == NULL)
- return;
-
- loc_mitm = (conn->loc_auth & 0x01) ? TRUE : FALSE;
- rem_mitm = (conn->rem_auth & 0x01) ? TRUE : FALSE;
-
- /* If we require MITM but the remote device can't provide that
- * (it has NoInputNoOutput) then reject the confirmation
- * request. The only exception is when we're dedicated bonding
- * initiators since then we always have the MITM bit set. */
- if (!conn->bonding_initiator && loc_mitm && conn->rem_cap == 0x03) {
- error("Rejecting request: remote device can't provide MITM");
- goto fail;
- }
-
- /* If no side requires MITM protection; auto-accept */
- if ((conn->loc_auth == 0xff || !loc_mitm || conn->rem_cap == 0x03) &&
- (!rem_mitm || conn->loc_cap == 0x03)) {
- DBG("auto accept of confirmation");
-
- /* Wait 5 milliseconds before doing auto-accept */
- usleep(5000);
-
- if (hciops_confirm_reply(index, &req->bdaddr,
- BDADDR_BREDR, TRUE) < 0)
- goto fail;
-
- return;
- }
-
- if (btd_event_user_confirm(&dev->bdaddr, &req->bdaddr,
- btohl(req->passkey)) == 0)
- return;
-
-fail:
- hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
- 6, ptr);
-}
-
-static void user_passkey_request(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_user_passkey_request *req = ptr;
-
- DBG("hci%d", index);
-
- if (btd_event_user_passkey(&dev->bdaddr, &req->bdaddr) < 0)
- hci_send_cmd(dev->sk, OGF_LINK_CTL,
- OCF_USER_PASSKEY_NEG_REPLY, 6, ptr);
-}
-
-static void user_passkey_notify(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_user_passkey_notify *req = ptr;
-
- DBG("hci%d", index);
-
- btd_event_user_notify(&dev->bdaddr, &req->bdaddr,
- btohl(req->passkey));
-}
-
-static gint oob_bdaddr_cmp(gconstpointer a, gconstpointer b)
-{
- const struct oob_data *data = a;
- const bdaddr_t *bdaddr = b;
-
- return bacmp(&data->bdaddr, bdaddr);
-}
-
-static void remote_oob_data_request(int index, bdaddr_t *bdaddr)
-{
- struct dev_info *dev = &devs[index];
- GSList *match;
-
- DBG("hci%d", index);
-
- match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
-
- if (match) {
- struct oob_data *data;
- remote_oob_data_reply_cp cp;
-
- data = match->data;
-
- bacpy(&cp.bdaddr, &data->bdaddr);
- memcpy(cp.hash, data->hash, sizeof(cp.hash));
- memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
-
- dev->oob_data = g_slist_delete_link(dev->oob_data, match);
-
- hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_REPLY,
- REMOTE_OOB_DATA_REPLY_CP_SIZE, &cp);
-
- } else {
- hci_send_cmd(dev->sk, OGF_LINK_CTL,
- OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, bdaddr);
- }
-}
-
-static int get_io_cap(int index, bdaddr_t *bdaddr, uint8_t *cap, uint8_t *auth)
-{
- struct dev_info *dev = &devs[index];
- struct bt_conn *conn;
- int err;
-
- conn = find_connection(dev, bdaddr);
- if (conn == NULL)
- return -ENOENT;
-
- err = get_auth_info(index, bdaddr, &conn->loc_auth);
- if (err < 0)
- return err;
-
- DBG("initial authentication requirement is 0x%02x", conn->loc_auth);
-
- if (!dev->pairable && !conn->bonding_initiator) {
- if (conn->rem_auth < 0x02) {
- DBG("Allowing no bonding in non-bondable mode");
- /* Kernel defaults to general bonding and so
- * overwrite for this special case. Otherwise
- * non-pairable test cases will fail. */
- conn->loc_auth = conn->rem_auth;
- goto done;
- }
-
- return -EPERM;
- }
-
- /* If the kernel doesn't know the local requirement just mirror
- * the remote one */
- if (conn->loc_auth == 0xff)
- conn->loc_auth = conn->rem_auth;
-
- if (conn->loc_auth == 0x00 || conn->loc_auth == 0x04) {
- /* If remote requests dedicated bonding follow that lead */
- if (conn->rem_auth == 0x02 || conn->rem_auth == 0x03) {
-
- /* If both remote and local IO capabilities allow MITM
- * then require it, otherwise don't */
- if (conn->rem_cap == 0x03 || conn->loc_cap == 0x03)
- conn->loc_auth = 0x02;
- else
- conn->loc_auth = 0x03;
- }
-
- /* If remote indicates no bonding then follow that. This
- * is important since the kernel might give general bonding
- * as default. */
- if (conn->rem_auth == 0x00 || conn->rem_auth == 0x01)
- conn->loc_auth = 0x00;
-
- /* If remote requires MITM then also require it, unless
- * our IO capability is NoInputNoOutput (so some
- * just-works security cases can be tested) */
- if (conn->rem_auth != 0xff && (conn->rem_auth & 0x01) &&
- conn->loc_cap != 0x03)
- conn->loc_auth |= 0x01;
- }
-
-done:
- *cap = conn->loc_cap;
- *auth = conn->loc_auth;
-
- DBG("final authentication requirement is 0x%02x", *auth);
-
- return 0;
-}
-
-static void io_capa_request(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- bdaddr_t *dba = ptr;
- uint8_t cap, auth = 0xff;
- char da[18];
- int err;
-
- ba2str(dba, da);
- DBG("hci%d IO capability request for %s", index, da);
-
- err = get_io_cap(index, dba, &cap, &auth);
- if (err < 0) {
- io_capability_neg_reply_cp cp;
-
- error("Getting IO capability failed: %s (%d)",
- strerror(-err), -err);
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, dba);
- cp.reason = HCI_PAIRING_NOT_ALLOWED;
- hci_send_cmd(dev->sk, OGF_LINK_CTL,
- OCF_IO_CAPABILITY_NEG_REPLY,
- IO_CAPABILITY_NEG_REPLY_CP_SIZE, &cp);
- } else {
- io_capability_reply_cp cp;
- struct bt_conn *conn;
- GSList *match;
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, dba);
- cp.capability = cap;
- cp.authentication = auth;
-
- conn = find_connection(dev, dba);
- match = g_slist_find_custom(dev->oob_data, dba, oob_bdaddr_cmp);
-
- if ((conn->bonding_initiator || conn->rem_oob_data == 0x01) &&
- match)
- cp.oob_data = 0x01;
- else
- cp.oob_data = 0x00;
-
- hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY,
- IO_CAPABILITY_REPLY_CP_SIZE, &cp);
- }
-}
-
-static void io_capa_response(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_io_capability_response *evt = ptr;
- struct bt_conn *conn;
- char da[18];
-
- ba2str(&evt->bdaddr, da);
- DBG("hci%d IO capability response from %s", index, da);
-
- conn = find_connection(dev, &evt->bdaddr);
- if (conn) {
- conn->rem_cap = evt->capability;
- conn->rem_auth = evt->authentication;
- conn->rem_oob_data = evt->oob_data;
- }
-}
-
-/* PIN code handling */
-
-static void pin_code_request(int index, bdaddr_t *dba)
-{
- struct dev_info *dev = &devs[index];
- struct bt_conn *conn;
- char addr[18];
- int err;
-
- ba2str(dba, addr);
- DBG("hci%d PIN request for %s", index, addr);
-
- conn = get_connection(dev, dba);
- if (conn->handle == 0)
- conn->secmode3 = TRUE;
-
- /* Check if the adapter is not pairable and if there isn't a bonding in
- * progress */
- if (!dev->pairable && !conn->bonding_initiator) {
- DBG("Rejecting PIN request in non-pairable mode");
- goto reject;
- }
-
- err = btd_event_request_pin(&dev->bdaddr, dba, FALSE);
- if (err < 0) {
- error("PIN code negative reply: %s", strerror(-err));
- goto reject;
- }
-
- return;
-
-reject:
- hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba);
-}
-
-static inline void remote_features_notify(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_remote_host_features_notify *evt = ptr;
-
- if (evt->features[0] & 0x01)
- btd_event_set_legacy_pairing(&dev->bdaddr, &evt->bdaddr,
- FALSE);
- else
- btd_event_set_legacy_pairing(&dev->bdaddr, &evt->bdaddr,
- TRUE);
-
- write_features_info(&dev->bdaddr, &evt->bdaddr, NULL, evt->features);
-}
-
-static void read_local_version_complete(int index,
- const read_local_version_rp *rp)
-{
- struct dev_info *dev = &devs[index];
-
- if (rp->status)
- return;
-
- dev->ver.manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
- dev->ver.hci_ver = rp->hci_ver;
- dev->ver.hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));
- dev->ver.lmp_ver = rp->lmp_ver;
- dev->ver.lmp_subver = btohs(bt_get_unaligned(&rp->lmp_subver));
-
- if (!dev->pending)
- return;
-
- hci_clear_bit(PENDING_VERSION, &dev->pending);
-
- DBG("Got version for hci%d", index);
-
- if (!dev->pending && dev->up)
- init_adapter(index);
-}
-
-static void read_local_features_complete(int index,
- const read_local_features_rp *rp)
-{
- struct dev_info *dev = &devs[index];
-
- if (rp->status)
- return;
-
- memcpy(dev->features, rp->features, 8);
-
- if (!dev->pending)
- return;
-
- hci_clear_bit(PENDING_FEATURES, &dev->pending);
-
- DBG("Got features for hci%d", index);
-
- if (!dev->pending && dev->up)
- init_adapter(index);
-}
-
-static void update_name(int index, const char *name)
-{
- struct btd_adapter *adapter;
-
- adapter = manager_find_adapter_by_id(index);
- if (adapter)
- adapter_name_changed(adapter, name);
-
- update_ext_inquiry_response(index);
-}
-
-static void read_local_name_complete(int index, read_local_name_rp *rp)
-{
- struct dev_info *dev = &devs[index];
-
- DBG("hci%d status %u", index, rp->status);
-
- if (rp->status)
- return;
-
- memcpy(dev->name, rp->name, 248);
-
- if (!dev->pending) {
- update_name(index, (char *) rp->name);
- return;
- }
-
- hci_clear_bit(PENDING_NAME, &dev->pending);
-
- DBG("Got name for hci%d", index);
-
- if (!dev->pending && dev->up)
- init_adapter(index);
-}
-
-static void read_tx_power_complete(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
-
- read_inq_response_tx_power_level_rp *rp = ptr;
-
- DBG("hci%d status %u", index, rp->status);
-
- if (rp->status)
- return;
-
- dev->tx_power = rp->level;
- update_ext_inquiry_response(index);
-}
-
-static void read_simple_pairing_mode_complete(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- read_simple_pairing_mode_rp *rp = ptr;
-
- DBG("hci%d status %u", index, rp->status);
-
- if (rp->status)
- return;
-
- dev->ssp_mode = rp->mode;
- update_ext_inquiry_response(index);
-}
-
-static void read_local_ext_features_complete(int index,
- const read_local_ext_features_rp *rp)
-{
- struct dev_info *dev = &devs[index];
-
- DBG("hci%d status %u", index, rp->status);
-
- if (rp->status)
- return;
-
- /* Local Extended feature page number is 1 */
- if (rp->page_num != 1)
- return;
-
- memcpy(dev->extfeatures, rp->features, sizeof(dev->extfeatures));
-}
-
-static void read_bd_addr_complete(int index, read_bd_addr_rp *rp)
-{
- struct dev_info *dev = &devs[index];
-
- DBG("hci%d status %u", index, rp->status);
-
- if (rp->status)
- return;
-
- bacpy(&dev->bdaddr, &rp->bdaddr);
-
- if (!dev->pending)
- return;
-
- hci_clear_bit(PENDING_BDADDR, &dev->pending);
-
- DBG("Got bdaddr for hci%d", index);
-
- if (!dev->pending && dev->up)
- init_adapter(index);
-}
-
-static inline void cs_inquiry_evt(int index, uint8_t status)
-{
- if (status) {
- error("Inquiry Failed with status 0x%02x", status);
- return;
- }
-
- set_state(index, DISCOV_INQ);
-}
-
-static inline void cmd_status(int index, void *ptr)
-{
- evt_cmd_status *evt = ptr;
- uint16_t opcode = btohs(evt->opcode);
-
- if (opcode == cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY))
- cs_inquiry_evt(index, evt->status);
-}
-
-static gboolean discoverable_timeout_handler(gpointer user_data)
-{
- struct dev_info *dev = user_data;
-
- hciops_set_discoverable(dev->id, FALSE, 0);
-
- return FALSE;
-}
-
-/* Limited Discoverable bit mask in CoD */
-#define LIMITED_BIT 0x002000
-
-static int hciops_set_limited_discoverable(int index, gboolean limited)
-{
- struct dev_info *dev = &devs[index];
- int num = (limited ? 2 : 1);
- uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
- write_current_iac_lap_cp cp;
-
- DBG("hci%d limited %d", index, limited);
-
- /* Check if limited bit needs to be set/reset */
- if (limited)
- dev->wanted_cod |= LIMITED_BIT;
- else
- dev->wanted_cod &= ~LIMITED_BIT;
-
- /* If we dont need the toggling, save an unnecessary CoD write */
- if (dev->pending_cod || dev->wanted_cod == dev->current_cod)
- return 0;
-
- /*
- * 1: giac
- * 2: giac + liac
- */
- memset(&cp, 0, sizeof(cp));
- cp.num_current_iac = num;
- memcpy(&cp.lap, lap, num * 3);
-
- if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_CURRENT_IAC_LAP,
- (num * 3 + 1), &cp) < 0)
- return -errno;
-
- return write_class(index, dev->wanted_cod);
-}
-
-static void reset_discoverable_timeout(int index)
-{
- struct dev_info *dev = &devs[index];
-
- if (dev->discoverable_id > 0) {
- g_source_remove(dev->discoverable_id);
- dev->discoverable_id = 0;
- }
-}
-
-static void set_discoverable_timeout(int index)
-{
- struct dev_info *dev = &devs[index];
-
- reset_discoverable_timeout(index);
-
- if (dev->discoverable_timeout == 0) {
- hciops_set_limited_discoverable(index, FALSE);
- return;
- }
-
- /* Set limited discoverable if pairable and interval between 0 to 60
- sec */
- if (dev->pairable && dev->discoverable_timeout <= 60)
- hciops_set_limited_discoverable(index, TRUE);
- else
- hciops_set_limited_discoverable(index, FALSE);
-
- dev->discoverable_id = g_timeout_add_seconds(dev->discoverable_timeout,
- discoverable_timeout_handler,
- dev);
-}
-
-static void read_scan_complete(int index, uint8_t status, void *ptr)
-{
- struct btd_adapter *adapter;
- read_scan_enable_rp *rp = ptr;
-
- DBG("hci%d status %u", index, status);
-
- switch (rp->enable) {
- case (SCAN_PAGE | SCAN_INQUIRY):
- case SCAN_INQUIRY:
- set_discoverable_timeout(index);
- break;
- default:
- reset_discoverable_timeout(index);
- hciops_set_limited_discoverable(index, FALSE);
- }
-
- adapter = manager_find_adapter_by_id(index);
- if (!adapter) {
- error("Unable to find matching adapter");
- return;
- }
-
- adapter_mode_changed(adapter, rp->enable);
-}
-
-static void write_class_complete(int index, uint8_t status)
-{
- struct dev_info *dev = &devs[index];
- struct btd_adapter *adapter;
-
- if (status)
- return;
-
- if (dev->pending_cod == 0)
- return;
-
- dev->current_cod = dev->pending_cod;
- dev->pending_cod = 0;
-
- adapter = manager_find_adapter(&dev->bdaddr);
- if (adapter)
- btd_adapter_class_changed(adapter, dev->current_cod);
-
- update_ext_inquiry_response(index);
-
- if (dev->wanted_cod == dev->current_cod)
- return;
-
- if (dev->wanted_cod & LIMITED_BIT &&
- !(dev->current_cod & LIMITED_BIT))
- hciops_set_limited_discoverable(index, TRUE);
- else if (!(dev->wanted_cod & LIMITED_BIT) &&
- (dev->current_cod & LIMITED_BIT))
- hciops_set_limited_discoverable(index, FALSE);
- else
- write_class(index, dev->wanted_cod);
-}
-
-static void read_local_oob_data_complete(int index, uint8_t status,
- read_local_oob_data_rp *rp)
-{
- struct btd_adapter *adapter = manager_find_adapter_by_id(index);
-
- if (!adapter)
- return;
-
- if (status)
- oob_read_local_data_complete(adapter, NULL, NULL);
- else
- oob_read_local_data_complete(adapter, rp->hash, rp->randomizer);
-}
-
-static inline void inquiry_complete_evt(int index, uint8_t status)
-{
- int adapter_type;
- struct btd_adapter *adapter;
-
- if (status) {
- error("Inquiry Failed with status 0x%02x", status);
- return;
- }
-
- adapter = manager_find_adapter_by_id(index);
- if (!adapter) {
- error("No matching adapter found");
- return;
- }
-
- adapter_type = get_adapter_type(index);
-
- if (adapter_type == BR_EDR_LE &&
- start_scanning(index, TIMEOUT_BR_LE_SCAN) == 0)
- return;
-
- set_state(index, DISCOV_NAMES);
-}
-
-static inline void cc_inquiry_cancel(int index, uint8_t status)
-{
- if (status) {
- error("Inquiry Cancel Failed with status 0x%02x", status);
- return;
- }
-
- set_state(index, DISCOV_HALTED);
-}
-
-static inline void cc_le_set_scan_enable(int index, uint8_t status)
-{
- struct dev_info *info = &devs[index];
-
- if (status) {
- error("LE Set Scan Enable Failed with status 0x%02x", status);
- return;
- }
-
- if (info->discov_state == DISCOV_SCAN)
- set_state(index, DISCOV_HALTED);
- else
- set_state(index, DISCOV_SCAN);
-}
-
-static inline void cmd_complete(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_cmd_complete *evt = ptr;
- uint16_t opcode = btohs(evt->opcode);
- uint8_t status = *((uint8_t *) ptr + EVT_CMD_COMPLETE_SIZE);
-
- switch (opcode) {
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION):
- ptr += sizeof(evt_cmd_complete);
- read_local_version_complete(index, ptr);
- break;
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES):
- ptr += sizeof(evt_cmd_complete);
- read_local_features_complete(index, ptr);
- break;
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES):
- ptr += sizeof(evt_cmd_complete);
- read_local_ext_features_complete(index, ptr);
- break;
- case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR):
- ptr += sizeof(evt_cmd_complete);
- read_bd_addr_complete(index, ptr);
- break;
- case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
- cc_inquiry_cancel(index, status);
- break;
- case cmd_opcode_pack(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE):
- cc_le_set_scan_enable(index, status);
- break;
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
- if (!status)
- hci_send_cmd(dev->sk, OGF_HOST_CTL,
- OCF_READ_LOCAL_NAME, 0, 0);
- break;
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
- hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_SCAN_ENABLE,
- 0, NULL);
- break;
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE):
- ptr += sizeof(evt_cmd_complete);
- read_scan_complete(index, status, ptr);
- break;
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
- write_class_complete(index, status);
- break;
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SIMPLE_PAIRING_MODE):
- if (!status)
- hci_send_cmd(dev->sk, OGF_HOST_CTL,
- OCF_READ_SIMPLE_PAIRING_MODE, 0, NULL);
- break;
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SIMPLE_PAIRING_MODE):
- ptr += sizeof(evt_cmd_complete);
- read_simple_pairing_mode_complete(index, ptr);
- break;
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME):
- ptr += sizeof(evt_cmd_complete);
- read_local_name_complete(index, ptr);
- break;
- case cmd_opcode_pack(OGF_HOST_CTL,
- OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL):
- ptr += sizeof(evt_cmd_complete);
- read_tx_power_complete(index, ptr);
- break;
- case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA):
- ptr += sizeof(evt_cmd_complete);
- read_local_oob_data_complete(index, status, ptr);
- break;
- };
-}
-
-static inline void remote_name_information(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_remote_name_req_complete *evt = ptr;
- struct btd_adapter *adapter;
- char name[MAX_NAME_LENGTH + 1];
- struct found_dev *found;
-
- GSList *match;
-
- DBG("hci%d status %u", index, evt->status);
-
- memset(name, 0, sizeof(name));
-
- if (evt->status == 0) {
- memcpy(name, evt->name, MAX_NAME_LENGTH);
- btd_event_remote_name(&dev->bdaddr, &evt->bdaddr, name);
- }
-
- adapter = manager_find_adapter_by_id(index);
- if (!adapter) {
- error("No matching adapter found");
- return;
- }
-
- match = g_slist_find_custom(dev->need_name, &evt->bdaddr,
- found_dev_bda_cmp);
- if (match == NULL)
- return;
-
- found = match->data;
- found->name_state = NAME_NOT_NEEDED;
-
- dev->need_name = g_slist_remove_link(dev->need_name, match);
-
- match->next = dev->found_devs;
- dev->found_devs = match;
- dev->found_devs = g_slist_sort(dev->found_devs, found_dev_rssi_cmp);
-
- if (resolve_names(dev, adapter) < 0)
- set_state(index, DISCOV_HALTED);
-}
-
-static inline void remote_version_information(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_read_remote_version_complete *evt = ptr;
- struct bt_conn *conn;
-
- DBG("hci%d status %u", index, evt->status);
-
- if (evt->status)
- return;
-
- conn = find_conn_by_handle(dev, btohs(evt->handle));
- if (conn == NULL)
- return;
-
- write_version_info(&dev->bdaddr, &conn->bdaddr,
- btohs(evt->manufacturer), evt->lmp_ver,
- btohs(evt->lmp_subver));
-}
-
-static void dev_found(struct dev_info *info, bdaddr_t *dba, uint8_t bdaddr_type,
- uint8_t *cod, int8_t rssi, uint8_t cfm_name,
- uint8_t *eir, size_t eir_len)
-{
- struct found_dev *dev;
- GSList *match;
-
- match = g_slist_find_custom(info->found_devs, dba, found_dev_bda_cmp);
- if (match != NULL) {
- cfm_name = 0;
- goto event;
- }
-
- dev = g_new0(struct found_dev, 1);
- bacpy(&dev->bdaddr, dba);
- dev->rssi = rssi;
- if (cfm_name)
- dev->name_state = NAME_UNKNOWN;
- else
- dev->name_state = NAME_NOT_NEEDED;
-
- if (cod && !eir_has_data_type(eir, eir_len, EIR_CLASS_OF_DEV))
- eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
- cod, 3);
-
- info->found_devs = g_slist_prepend(info->found_devs, dev);
-
-event:
- btd_event_device_found(&info->bdaddr, dba, bdaddr_type, rssi, cfm_name,
- eir, eir_len);
-}
-
-static inline void inquiry_result(int index, int plen, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- uint8_t num = *(uint8_t *) ptr++;
- int i;
-
- for (i = 0; i < num; i++) {
- inquiry_info *info = ptr;
- uint8_t eir[5];
-
- memset(eir, 0, sizeof(eir));
- dev_found(dev, &info->bdaddr, BDADDR_BREDR, info->dev_class,
- 0, 1, eir, 0);
- ptr += INQUIRY_INFO_SIZE;
- }
-}
-
-static inline void inquiry_result_with_rssi(int index, int plen, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- uint8_t num = *(uint8_t *) ptr++;
- uint8_t eir[5];
- int i;
-
- if (!num)
- return;
-
- if ((plen - 1) / num == INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE) {
- for (i = 0; i < num; i++) {
- inquiry_info_with_rssi_and_pscan_mode *info = ptr;
-
- memset(eir, 0, sizeof(eir));
- dev_found(dev, &info->bdaddr, BDADDR_BREDR,
- info->dev_class, info->rssi,
- 1, eir, 0);
- ptr += INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE;
- }
- } else {
- for (i = 0; i < num; i++) {
- inquiry_info_with_rssi *info = ptr;
-
- memset(eir, 0, sizeof(eir));
- dev_found(dev, &info->bdaddr, BDADDR_BREDR,
- info->dev_class, info->rssi,
- 1, eir, 0);
- ptr += INQUIRY_INFO_WITH_RSSI_SIZE;
- }
- }
-}
-
-static inline void extended_inquiry_result(int index, int plen, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- uint8_t num = *(uint8_t *) ptr++;
- int i;
-
- for (i = 0; i < num; i++) {
- extended_inquiry_info *info = ptr;
- uint8_t eir[sizeof(info->data) + 5];
- gboolean cfm_name;
- size_t eir_len;
-
- eir_len = eir_length(info->data, sizeof(info->data));
-
- memset(eir, 0, sizeof(eir));
- memcpy(eir, info->data, eir_len);
-
- if (eir_has_data_type(eir, eir_len, EIR_NAME_COMPLETE))
- cfm_name = FALSE;
- else
- cfm_name = TRUE;
-
- dev_found(dev, &info->bdaddr, BDADDR_BREDR, info->dev_class,
- info->rssi, cfm_name, eir, eir_len);
- ptr += EXTENDED_INQUIRY_INFO_SIZE;
- }
-}
-
-static inline void remote_features_information(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_read_remote_features_complete *evt = ptr;
- struct bt_conn *conn;
-
- DBG("hci%d status %u", index, evt->status);
-
- if (evt->status)
- return;
-
- conn = find_conn_by_handle(dev, btohs(evt->handle));
- if (conn == NULL)
- return;
-
- write_features_info(&dev->bdaddr, &conn->bdaddr, evt->features, NULL);
-}
-
-struct remote_version_req {
- int index;
- uint16_t handle;
-};
-
-static gboolean __get_remote_version(gpointer user_data)
-{
- struct remote_version_req *req = user_data;
- struct dev_info *dev = &devs[req->index];
- read_remote_version_cp cp;
-
- DBG("hci%d handle %u", req->index, req->handle);
-
- memset(&cp, 0, sizeof(cp));
- cp.handle = htobs(req->handle);
-
- hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_READ_REMOTE_VERSION,
- READ_REMOTE_VERSION_CP_SIZE, &cp);
-
- return FALSE;
-}
-
-static void get_remote_version(int index, uint16_t handle)
-{
- struct remote_version_req *req;
-
- req = g_new0(struct remote_version_req, 1);
- req->handle = handle;
- req->index = index;
-
- g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, 1, __get_remote_version,
- req, g_free);
-}
-
-static void conn_free(struct bt_conn *conn)
-{
- if (conn->io != NULL) {
- g_io_channel_shutdown(conn->io, TRUE, NULL);
- g_io_channel_unref(conn->io);
- }
-
- g_free(conn);
-}
-
-static inline void conn_failed(int index, bdaddr_t *bdaddr, uint8_t status)
-{
- struct dev_info *dev = &devs[index];
- struct bt_conn *conn;
-
- btd_event_conn_failed(&dev->bdaddr, bdaddr, status);
-
- conn = find_connection(dev, bdaddr);
- if (conn == NULL)
- return;
-
- bonding_complete(dev, conn, status);
-
- dev->connections = g_slist_remove(dev->connections, conn);
- conn_free(conn);
-}
-
-static inline void conn_complete(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_conn_complete *evt = ptr;
- char filename[PATH_MAX];
- char local_addr[18], peer_addr[18], *str;
- struct bt_conn *conn;
-
- if (evt->link_type != ACL_LINK)
- return;
-
- DBG("status 0x%02x", evt->status);
-
- if (evt->status != 0) {
- conn_failed(index, &evt->bdaddr, evt->status);
- return;
- }
-
- conn = get_connection(dev, &evt->bdaddr);
- conn->handle = btohs(evt->handle);
-
- btd_event_conn_complete(&dev->bdaddr, &evt->bdaddr, BDADDR_BREDR,
- NULL, NULL);
-
- if (conn->secmode3)
- bonding_complete(dev, conn, 0);
-
- /* check if the remote version needs be requested */
- ba2str(&dev->bdaddr, local_addr);
- ba2str(&evt->bdaddr, peer_addr);
-
- create_name(filename, sizeof(filename), STORAGEDIR, local_addr,
- "manufacturers");
-
- str = textfile_get(filename, peer_addr);
- if (!str)
- get_remote_version(index, btohs(evt->handle));
- else
- free(str);
-}
-
-static inline uint8_t le_addr_type(uint8_t bdaddr_type)
-{
- switch (bdaddr_type) {
- case LE_RANDOM_ADDRESS:
- return BDADDR_LE_RANDOM;
- case LE_PUBLIC_ADDRESS:
- default:
- return BDADDR_LE_PUBLIC;
- }
-}
-
-static inline void le_conn_complete(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_le_connection_complete *evt = ptr;
- char filename[PATH_MAX];
- char local_addr[18], peer_addr[18], *str;
- struct bt_conn *conn;
- uint8_t bdaddr_type;
-
- if (evt->status) {
- btd_event_conn_failed(&dev->bdaddr, &evt->peer_bdaddr,
- evt->status);
- return;
- }
-
- conn = get_connection(dev, &evt->peer_bdaddr);
- conn->handle = btohs(evt->handle);
-
- bdaddr_type = le_addr_type(evt->peer_bdaddr_type);
- btd_event_conn_complete(&dev->bdaddr, &evt->peer_bdaddr, bdaddr_type,
- NULL, NULL);
-
- /* check if the remote version needs be requested */
- ba2str(&dev->bdaddr, local_addr);
- ba2str(&evt->peer_bdaddr, peer_addr);
-
- create_name(filename, sizeof(filename), STORAGEDIR, local_addr,
- "manufacturers");
-
- str = textfile_get(filename, peer_addr);
- if (!str)
- get_remote_version(index, btohs(evt->handle));
- else
- free(str);
-}
-
-static inline void disconn_complete(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_disconn_complete *evt = ptr;
- struct bt_conn *conn;
-
- DBG("handle %u status 0x%02x", btohs(evt->handle), evt->status);
-
- if (evt->status != 0)
- return;
-
- conn = find_conn_by_handle(dev, btohs(evt->handle));
- if (conn == NULL)
- return;
-
- dev->connections = g_slist_remove(dev->connections, conn);
-
- btd_event_disconn_complete(&dev->bdaddr, &conn->bdaddr);
-
- conn_free(conn);
-}
-
-static inline void auth_complete(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_auth_complete *evt = ptr;
- struct bt_conn *conn;
-
- DBG("hci%d status %u", index, evt->status);
-
- conn = find_conn_by_handle(dev, btohs(evt->handle));
- if (conn == NULL)
- return;
-
- bonding_complete(dev, conn, evt->status);
-}
-
-static inline void simple_pairing_complete(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_simple_pairing_complete *evt = ptr;
-
- DBG("hci%d status %u", index, evt->status);
-
- btd_event_simple_pairing_complete(&dev->bdaddr, &evt->bdaddr,
- evt->status);
-}
-
-static inline void conn_request(int index, void *ptr)
-{
- struct dev_info *dev = &devs[index];
- evt_conn_request *evt = ptr;
- uint32_t class = evt->dev_class[0] | (evt->dev_class[1] << 8)
- | (evt->dev_class[2] << 16);
-
- btd_event_remote_class(&dev->bdaddr, &evt->bdaddr, class);
-}
-
-static inline void le_advertising_report(int index, evt_le_meta_event *meta)
-{
- struct dev_info *dev = &devs[index];
- le_advertising_info *info;
- uint8_t num_reports, rssi;
- const uint8_t RSSI_SIZE = 1;
-
- num_reports = meta->data[0];
-
- info = (le_advertising_info *) &meta->data[1];
- rssi = *(info->data + info->length);
-
- dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type), NULL,
- rssi, 0, info->data, info->length);
-
- num_reports--;
-
- while (num_reports--) {
- info = (le_advertising_info *) (info->data + info->length +
- RSSI_SIZE);
- rssi = *(info->data + info->length);
-
- dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type),
- NULL, rssi, 0, info->data, info->length);
- }
-}
-
-static inline void le_metaevent(int index, void *ptr)
-{
- evt_le_meta_event *meta = ptr;
-
- DBG("hci%d LE Meta Event %u", index, meta->subevent);
-
- switch (meta->subevent) {
- case EVT_LE_ADVERTISING_REPORT:
- le_advertising_report(index, meta);
- break;
-
- case EVT_LE_CONN_COMPLETE:
- le_conn_complete(index, meta->data);
- break;
- }
-}
-
-static void stop_hci_dev(int index)
-{
- struct dev_info *dev = &devs[index];
-
- if (dev->sk < 0)
- return;
-
- info("Stopping hci%d event socket", index);
-
- if (dev->watch_id > 0)
- g_source_remove(dev->watch_id);
-
- if (dev->stop_scan_id > 0)
- g_source_remove(dev->stop_scan_id);
-
- if (dev->io != NULL)
- g_io_channel_unref(dev->io);
-
- hci_close_dev(dev->sk);
-
- g_slist_free_full(dev->keys, g_free);
- g_slist_free_full(dev->uuids, g_free);
- g_slist_free_full(dev->connections, g_free);
-
- init_dev_info(index, -1, dev->registered, dev->already_up);
-}
-
-static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
- gpointer data)
-{
- unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf;
- int type, index = GPOINTER_TO_INT(data);
- struct dev_info *dev = &devs[index];
- struct hci_dev_info di;
- ssize_t len;
- hci_event_hdr *eh;
- evt_cmd_status *evt;
- int fd;
-
- if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
- stop_hci_dev(index);
- return FALSE;
- }
-
- fd = g_io_channel_unix_get_fd(chan);
-
- len = read(fd, buf, sizeof(buf));
- if (len < 0) {
- if (errno == EAGAIN)
- return TRUE;
- stop_hci_dev(index);
- return FALSE;
- }
-
- type = *ptr++;
-
- if (type != HCI_EVENT_PKT)
- return TRUE;
-
- eh = (hci_event_hdr *) ptr;
- ptr += HCI_EVENT_HDR_SIZE;
-
- memset(&di, 0, sizeof(di));
- if (hci_devinfo(index, &di) == 0) {
- bacpy(&dev->bdaddr, &di.bdaddr);
-
- if (ignore_device(&di))
- return TRUE;
- }
-
- switch (eh->evt) {
- case EVT_CMD_STATUS:
- cmd_status(index, ptr);
- break;
-
- case EVT_CMD_COMPLETE:
- cmd_complete(index, ptr);
- break;
-
- case EVT_REMOTE_NAME_REQ_COMPLETE:
- remote_name_information(index, ptr);
- break;
-
- case EVT_READ_REMOTE_VERSION_COMPLETE:
- remote_version_information(index, ptr);
- break;
-
- case EVT_READ_REMOTE_FEATURES_COMPLETE:
- remote_features_information(index, ptr);
- break;
-
- case EVT_REMOTE_HOST_FEATURES_NOTIFY:
- remote_features_notify(index, ptr);
- break;
-
- case EVT_INQUIRY_COMPLETE:
- evt = (evt_cmd_status *) ptr;
- inquiry_complete_evt(index, evt->status);
- break;
-
- case EVT_INQUIRY_RESULT:
- inquiry_result(index, eh->plen, ptr);
- break;
-
- case EVT_INQUIRY_RESULT_WITH_RSSI:
- inquiry_result_with_rssi(index, eh->plen, ptr);
- break;
-
- case EVT_EXTENDED_INQUIRY_RESULT:
- extended_inquiry_result(index, eh->plen, ptr);
- break;
-
- case EVT_CONN_COMPLETE:
- conn_complete(index, ptr);
- break;
-
- case EVT_DISCONN_COMPLETE:
- disconn_complete(index, ptr);
- break;
-
- case EVT_AUTH_COMPLETE:
- auth_complete(index, ptr);
- break;
-
- case EVT_SIMPLE_PAIRING_COMPLETE:
- simple_pairing_complete(index, ptr);
- break;
-
- case EVT_CONN_REQUEST:
- conn_request(index, ptr);
- break;
- case EVT_LE_META_EVENT:
- le_metaevent(index, ptr);
- break;
- case EVT_PIN_CODE_REQ:
- pin_code_request(index, (bdaddr_t *) ptr);
- break;
-
- case EVT_LINK_KEY_REQ:
- link_key_request(index, (bdaddr_t *) ptr);
- break;
-
- case EVT_LINK_KEY_NOTIFY:
- link_key_notify(index, ptr);
- break;
-
- case EVT_RETURN_LINK_KEYS:
- return_link_keys(index, ptr);
- break;
-
- case EVT_IO_CAPABILITY_REQUEST:
- io_capa_request(index, ptr);
- break;
-
- case EVT_IO_CAPABILITY_RESPONSE:
- io_capa_response(index, ptr);
- break;
-
- case EVT_USER_CONFIRM_REQUEST:
- user_confirm_request(index, ptr);
- break;
-
- case EVT_USER_PASSKEY_REQUEST:
- user_passkey_request(index, ptr);
- break;
-
- case EVT_USER_PASSKEY_NOTIFY:
- user_passkey_notify(index, ptr);
- break;
-
- case EVT_REMOTE_OOB_DATA_REQUEST:
- remote_oob_data_request(index, (bdaddr_t *) ptr);
- break;
- }
-
- return TRUE;
-}
-
-static void start_hci_dev(int index)
-{
- struct dev_info *dev = &devs[index];
- GIOChannel *chan = dev->io;
- GIOCondition cond;
- struct hci_filter flt;
-
- if (chan)
- return;
-
- info("Listening for HCI events on hci%d", index);
-
- /* Set filter */
- hci_filter_clear(&flt);
- hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
- hci_filter_set_event(EVT_CMD_STATUS, &flt);
- hci_filter_set_event(EVT_CMD_COMPLETE, &flt);
- hci_filter_set_event(EVT_PIN_CODE_REQ, &flt);
- hci_filter_set_event(EVT_LINK_KEY_REQ, &flt);
- hci_filter_set_event(EVT_LINK_KEY_NOTIFY, &flt);
- hci_filter_set_event(EVT_RETURN_LINK_KEYS, &flt);
- hci_filter_set_event(EVT_IO_CAPABILITY_REQUEST, &flt);
- hci_filter_set_event(EVT_IO_CAPABILITY_RESPONSE, &flt);
- hci_filter_set_event(EVT_USER_CONFIRM_REQUEST, &flt);
- hci_filter_set_event(EVT_USER_PASSKEY_REQUEST, &flt);
- hci_filter_set_event(EVT_REMOTE_OOB_DATA_REQUEST, &flt);
- hci_filter_set_event(EVT_USER_PASSKEY_NOTIFY, &flt);
- hci_filter_set_event(EVT_KEYPRESS_NOTIFY, &flt);
- hci_filter_set_event(EVT_SIMPLE_PAIRING_COMPLETE, &flt);
- hci_filter_set_event(EVT_AUTH_COMPLETE, &flt);
- hci_filter_set_event(EVT_REMOTE_NAME_REQ_COMPLETE, &flt);
- hci_filter_set_event(EVT_READ_REMOTE_VERSION_COMPLETE, &flt);
- hci_filter_set_event(EVT_READ_REMOTE_FEATURES_COMPLETE, &flt);
- hci_filter_set_event(EVT_REMOTE_HOST_FEATURES_NOTIFY, &flt);
- hci_filter_set_event(EVT_INQUIRY_COMPLETE, &flt);
- hci_filter_set_event(EVT_INQUIRY_RESULT, &flt);
- hci_filter_set_event(EVT_INQUIRY_RESULT_WITH_RSSI, &flt);
- hci_filter_set_event(EVT_EXTENDED_INQUIRY_RESULT, &flt);
- hci_filter_set_event(EVT_CONN_REQUEST, &flt);
- hci_filter_set_event(EVT_CONN_COMPLETE, &flt);
- hci_filter_set_event(EVT_DISCONN_COMPLETE, &flt);
- hci_filter_set_event(EVT_LE_META_EVENT, &flt);
- if (setsockopt(dev->sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
- error("Can't set filter on hci%d: %s (%d)",
- index, strerror(errno), errno);
- return;
- }
-
- chan = g_io_channel_unix_new(dev->sk);
- cond = G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR;
- dev->watch_id = g_io_add_watch_full(chan, G_PRIORITY_LOW, cond,
- io_security_event,
- GINT_TO_POINTER(index), NULL);
- dev->io = chan;
- dev->pin_length = 0;
-
-}
-
-/* End of HCI event callbacks */
-
-static gboolean child_exit(GIOChannel *io, GIOCondition cond, void *user_data)
-{
- int status, fd = g_io_channel_unix_get_fd(io);
- pid_t child_pid;
-
- if (read(fd, &child_pid, sizeof(child_pid)) != sizeof(child_pid)) {
- error("child_exit: unable to read child pid from pipe");
- return TRUE;
- }
-
- if (waitpid(child_pid, &status, 0) != child_pid)
- error("waitpid(%d) failed", child_pid);
- else
- DBG("child %d exited", child_pid);
-
- return TRUE;
-}
-
-static void at_child_exit(void)
-{
- pid_t pid = getpid();
-
- if (write(child_pipe[1], &pid, sizeof(pid)) != sizeof(pid))
- error("unable to write to child pipe");
-}
-
-static void device_devup_setup(int index)
-{
- struct dev_info *dev = &devs[index];
- struct hci_dev_info di;
- read_stored_link_key_cp cp;
-
- DBG("hci%d", index);
-
- if (hci_devinfo(index, &di) < 0)
- return;
-
- if (ignore_device(&di))
- return;
-
- bacpy(&dev->bdaddr, &di.bdaddr);
- memcpy(dev->features, di.features, 8);
-
- if (dev->features[7] & LMP_EXT_FEAT) {
- uint8_t page_num = 0x01;
-
- hci_send_cmd(dev->sk, OGF_INFO_PARAM,
- OCF_READ_LOCAL_EXT_FEATURES, 1, &page_num);
- }
-
- /* Set page timeout */
- if ((main_opts.flags & (1 << HCID_SET_PAGETO))) {
- write_page_timeout_cp cp;
-
- cp.timeout = htobs(main_opts.pageto);
- hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_PAGE_TIMEOUT,
- WRITE_PAGE_TIMEOUT_CP_SIZE, &cp);
- }
-
- bacpy(&cp.bdaddr, BDADDR_ANY);
- cp.read_all = 1;
- hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_STORED_LINK_KEY,
- READ_STORED_LINK_KEY_CP_SIZE, &cp);
-
- if (!dev->pending) {
- init_adapter(index);
- return;
- }
-
- /* Even though it shouldn't happen (assuming the kernel behaves
- * properly) it seems like we might miss the very first
- * initialization commands that the kernel sends. So check for
- * it here and resend the ones we haven't seen their results yet */
-
- if (hci_test_bit(PENDING_FEATURES, &dev->pending))
- hci_send_cmd(dev->sk, OGF_INFO_PARAM,
- OCF_READ_LOCAL_FEATURES, 0, NULL);
-
- if (hci_test_bit(PENDING_VERSION, &dev->pending))
- hci_send_cmd(dev->sk, OGF_INFO_PARAM,
- OCF_READ_LOCAL_VERSION, 0, NULL);
-
- if (hci_test_bit(PENDING_NAME, &dev->pending))
- hci_send_cmd(dev->sk, OGF_HOST_CTL,
- OCF_READ_LOCAL_NAME, 0, 0);
-
- if (hci_test_bit(PENDING_BDADDR, &dev->pending))
- hci_send_cmd(dev->sk, OGF_INFO_PARAM,
- OCF_READ_BD_ADDR, 0, NULL);
-}
-
-static void init_pending(int index)
-{
- struct dev_info *dev = &devs[index];
-
- hci_set_bit(PENDING_BDADDR, &dev->pending);
- hci_set_bit(PENDING_VERSION, &dev->pending);
- hci_set_bit(PENDING_FEATURES, &dev->pending);
- hci_set_bit(PENDING_NAME, &dev->pending);
-}
-
-static struct dev_info *init_device(int index, gboolean already_up)
-{
- struct dev_info *dev;
- struct hci_dev_req dr;
- int dd;
- pid_t pid;
-
- DBG("hci%d", index);
-
- dd = hci_open_dev(index);
- if (dd < 0) {
- error("Unable to open hci%d: %s (%d)", index,
- strerror(errno), errno);
- return NULL;
- }
-
- if (index > max_dev) {
- max_dev = index;
- devs = g_realloc(devs, sizeof(devs[0]) * (max_dev + 1));
- }
-
- dev = init_dev_info(index, dd, FALSE, already_up);
- init_pending(index);
- start_hci_dev(index);
-
- /* Avoid forking if nothing else has to be done */
- if (already_up)
- return dev;
-
- /* Do initialization in the separate process */
- pid = fork();
- switch (pid) {
- case 0:
- atexit(at_child_exit);
- break;
- case -1:
- error("Fork failed. Can't init device hci%d: %s (%d)",
- index, strerror(errno), errno);
- default:
- DBG("child %d forked", pid);
- return dev;
- }
-
- memset(&dr, 0, sizeof(dr));
- dr.dev_id = index;
-
- /* Set link mode */
- dr.dev_opt = main_opts.link_mode;
- if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0)
- error("Can't set link mode on hci%d: %s (%d)",
- index, strerror(errno), errno);
-
- /* Start HCI device */
- if (ioctl(dd, HCIDEVUP, index) < 0 && errno != EALREADY) {
- error("Can't init device hci%d: %s (%d)",
- index, strerror(errno), errno);
- goto fail;
- }
-
- hci_close_dev(dd);
- exit(0);
-
-fail:
- hci_close_dev(dd);
- exit(1);
-}
-
-static void init_conn_list(int index)
-{
- struct dev_info *dev = &devs[index];
- struct hci_conn_list_req *cl;
- struct hci_conn_info *ci;
- int i;
-
- DBG("hci%d", index);
-
- cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl));
-
- cl->dev_id = index;
- cl->conn_num = 10;
- ci = cl->conn_info;
-
- if (ioctl(dev->sk, HCIGETCONNLIST, cl) < 0) {
- error("Unable to get connection list: %s (%d)",
- strerror(errno), errno);
- goto failed;
- }
-
- for (i = 0; i < cl->conn_num; i++, ci++) {
- struct bt_conn *conn;
-
- if (ci->type != ACL_LINK)
- continue;
-
- conn = get_connection(dev, &ci->bdaddr);
- conn->handle = ci->handle;
- }
-
-failed:
- g_free(cl);
-}
-
-static void device_event(int event, int index)
-{
- switch (event) {
- case HCI_DEV_REG:
- info("HCI dev %d registered", index);
- init_device(index, FALSE);
- break;
-
- case HCI_DEV_UNREG:
- info("HCI dev %d unregistered", index);
- stop_hci_dev(index);
- if (devs[index].registered)
- btd_manager_unregister_adapter(index);
- break;
-
- case HCI_DEV_UP:
- info("HCI dev %d up", index);
- devs[index].up = TRUE;
- device_devup_setup(index);
- break;
-
- case HCI_DEV_DOWN:
- info("HCI dev %d down", index);
- devs[index].up = FALSE;
- devs[index].pending_cod = 0;
- devs[index].cache_enable = TRUE;
- devs[index].discov_state = DISCOV_HALTED;
- reset_discoverable_timeout(index);
- if (!devs[index].pending) {
- struct btd_adapter *adapter;
-
- adapter = manager_find_adapter_by_id(index);
- if (adapter)
- btd_adapter_stop(adapter);
-
- init_pending(index);
- }
- break;
- }
-}
-
-static gboolean init_known_adapters(gpointer user_data)
-{
- struct hci_dev_list_req *dl;
- struct hci_dev_req *dr;
- int i, err, ctl = GPOINTER_TO_INT(user_data);
- size_t req_size;
-
- DBG("");
-
- req_size = HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t);
-
- dl = g_try_malloc0(req_size);
- if (!dl) {
- error("Can't allocate devlist buffer");
- return FALSE;
- }
-
- dl->dev_num = HCI_MAX_DEV;
- dr = dl->dev_req;
-
- if (ioctl(ctl, HCIGETDEVLIST, dl) < 0) {
- err = -errno;
- error("Can't get device list: %s (%d)", strerror(-err), -err);
- g_free(dl);
- return FALSE;
- }
-
- for (i = 0; i < dl->dev_num; i++, dr++) {
- struct dev_info *dev;
- gboolean already_up;
-
- already_up = hci_test_bit(HCI_UP, &dr->dev_opt);
-
- dev = init_device(dr->dev_id, already_up);
- if (dev == NULL)
- continue;
-
- if (!dev->already_up)
- continue;
-
- init_conn_list(dr->dev_id);
-
- dev->pending = 0;
- hci_set_bit(PENDING_VERSION, &dev->pending);
- hci_send_cmd(dev->sk, OGF_INFO_PARAM,
- OCF_READ_LOCAL_VERSION, 0, NULL);
- device_event(HCI_DEV_UP, dr->dev_id);
- }
-
- g_free(dl);
-
- return FALSE;
-}
-
-static gboolean io_stack_event(GIOChannel *chan, GIOCondition cond,
- gpointer data)
-{
- unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
- evt_stack_internal *si;
- evt_si_device *sd;
- hci_event_hdr *eh;
- int type, fd;
- ssize_t len;
-
- ptr = buf;
-
- fd = g_io_channel_unix_get_fd(chan);
-
- len = read(fd, buf, sizeof(buf));
- if (len < 0) {
- if (errno == EAGAIN)
- return TRUE;
-
- error("Read from control socket failed: %s (%d)",
- strerror(errno), errno);
- return FALSE;
- }
-
- type = *ptr++;
-
- if (type != HCI_EVENT_PKT)
- return TRUE;
-
- eh = (hci_event_hdr *) ptr;
- if (eh->evt != EVT_STACK_INTERNAL)
- return TRUE;
-
- ptr += HCI_EVENT_HDR_SIZE;
-
- si = (evt_stack_internal *) ptr;
- switch (si->type) {
- case EVT_SI_DEVICE:
- sd = (void *) &si->data;
- device_event(sd->event, sd->dev_id);
- break;
- }
-
- return TRUE;
-}
-
-static int hciops_setup(void)
-{
- struct sockaddr_hci addr;
- struct hci_filter flt;
- GIOChannel *ctl_io, *child_io;
- int sock, err;
-
- DBG("");
-
- if (child_pipe[0] != -1)
- return -EALREADY;
-
- if (pipe(child_pipe) < 0) {
- err = -errno;
- error("pipe(): %s (%d)", strerror(-err), -err);
- return err;
- }
-
- child_io = g_io_channel_unix_new(child_pipe[0]);
- g_io_channel_set_close_on_unref(child_io, TRUE);
- child_io_id = g_io_add_watch(child_io,
- G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- child_exit, NULL);
- g_io_channel_unref(child_io);
-
- /* Create and bind HCI socket */
- sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
- if (sock < 0) {
- err = -errno;
- error("Can't open HCI socket: %s (%d)", strerror(-err),
- -err);
- return err;
- }
-
- /* Set filter */
- hci_filter_clear(&flt);
- hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
- hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
- if (setsockopt(sock, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
- err = -errno;
- error("Can't set filter: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.hci_family = AF_BLUETOOTH;
- addr.hci_dev = HCI_DEV_NONE;
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- err = -errno;
- error("Can't bind HCI socket: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- ctl_io = g_io_channel_unix_new(sock);
- g_io_channel_set_close_on_unref(ctl_io, TRUE);
-
- ctl_io_id = g_io_add_watch(ctl_io, G_IO_IN, io_stack_event, NULL);
-
- g_io_channel_unref(ctl_io);
-
- g_idle_add(init_known_adapters, GINT_TO_POINTER(sock));
-
- return 0;
-}
-
-static void hciops_cleanup(void)
-{
- int i;
-
- DBG("");
-
- for (i = 0; i <= max_dev; i++)
- stop_hci_dev(i);
-
- g_free(devs);
- devs = NULL;
- max_dev = -1;
-
- if (child_io_id) {
- g_source_remove(child_io_id);
- child_io_id = 0;
- }
-
- if (ctl_io_id) {
- g_source_remove(ctl_io_id);
- ctl_io_id = 0;
- }
-
- if (child_pipe[0] >= 0) {
- close(child_pipe[0]);
- child_pipe[0] = -1;
- }
-
- if (child_pipe[1] >= 0) {
- close(child_pipe[1]);
- child_pipe[1] = -1;
- }
-}
-
-static int hciops_set_powered(int index, gboolean powered)
-{
- struct dev_info *dev = &devs[index];
- int err;
-
- DBG("hci%d powered %d", index, powered);
-
- if (powered == FALSE)
- return hciops_power_off(index);
-
- if (ioctl(dev->sk, HCIDEVUP, index) == 0)
- return 0;
-
- if (errno == EALREADY)
- return 0;
-
- err = -errno;
- error("Can't init device hci%d: %s (%d)",
- index, strerror(-err), -err);
-
- return err;
-}
-
-static int start_inquiry(int index, uint8_t length)
-{
- struct dev_info *dev = &devs[index];
- uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
- inquiry_cp inq_cp;
-
- DBG("hci%d length %u", index, length);
-
- memset(&inq_cp, 0, sizeof(inq_cp));
- memcpy(&inq_cp.lap, lap, 3);
- inq_cp.length = length;
- inq_cp.num_rsp = 0x00;
-
- if (hci_send_cmd(dev->sk, OGF_LINK_CTL,
- OCF_INQUIRY, INQUIRY_CP_SIZE, &inq_cp) < 0)
- return -errno;
-
- return 0;
-}
-
-static int le_set_scan_enable(int index, uint8_t enable)
-{
- struct dev_info *dev = &devs[index];
- le_set_scan_enable_cp cp;
-
- DBG("hci%d enable %u", index, enable);
-
- memset(&cp, 0, sizeof(cp));
- cp.enable = enable;
- cp.filter_dup = 0;
-
- if (hci_send_cmd(dev->sk, OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE,
- LE_SET_SCAN_ENABLE_CP_SIZE, &cp) < 0)
- return -errno;
-
- return 0;
-}
-
-static gboolean stop_le_scan_cb(gpointer user_data)
-{
- struct dev_info *dev = user_data;
- int err;
-
- err = le_set_scan_enable(dev->id, 0);
- if (err < 0)
- return TRUE;
-
- dev->stop_scan_id = 0;
-
- return FALSE;
-}
-
-static int start_scanning(int index, int timeout)
-{
- struct dev_info *dev = &devs[index];
- le_set_scan_parameters_cp cp;
- int err;
-
- DBG("hci%d", index);
-
- memset(&cp, 0, sizeof(cp));
- cp.type = 0x01; /* Active scanning */
- /* The recommended value for scan interval and window is 11.25 msec.
- * It is calculated by: time = n * 0.625 msec */
- cp.interval = htobs(0x0012);
- cp.window = htobs(0x0012);
- cp.own_bdaddr_type = 0; /* Public address */
- cp.filter = 0; /* Accept all adv packets */
-
- if (hci_send_cmd(dev->sk, OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS,
- LE_SET_SCAN_PARAMETERS_CP_SIZE, &cp) < 0)
- return -errno;
-
- err = le_set_scan_enable(index, 1);
- if (err < 0)
- return err;
-
- /* Schedule a le scan disable in 'timeout' milliseconds */
- dev->stop_scan_id = g_timeout_add(timeout, stop_le_scan_cb, dev);
-
- return 0;
-}
-
-static int hciops_stop_scanning(int index)
-{
- struct dev_info *dev = &devs[index];
-
- DBG("hci%d", index);
-
- if (dev->stop_scan_id > 0) {
- g_source_remove(dev->stop_scan_id);
- dev->stop_scan_id = 0;
- }
-
- return le_set_scan_enable(index, 0);
-}
-
-static int cancel_resolve_name(int index)
-{
- struct dev_info *info = &devs[index];
- struct found_dev *dev;
- remote_name_req_cancel_cp cp;
- struct btd_adapter *adapter;
-
- DBG("hci%d", index);
-
- if (g_slist_length(info->need_name) == 0)
- return 0;
-
- dev = info->need_name->data;
- if (dev->name_state != NAME_PENDING)
- return 0;
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, &dev->bdaddr);
-
- adapter = manager_find_adapter_by_id(index);
- if (adapter)
- adapter_set_discovering(adapter, FALSE);
-
- found_dev_cleanup(info);
-
- if (hci_send_cmd(info->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL,
- REMOTE_NAME_REQ_CANCEL_CP_SIZE, &cp) < 0)
- return -errno;
-
- return 0;
-}
-
-static int hciops_start_discovery(int index)
-{
- int adapter_type = get_adapter_type(index);
-
- DBG("hci%u", index);
-
- switch (adapter_type) {
- case BR_EDR_LE:
- return start_inquiry(index, LENGTH_BR_LE_INQ);
- case BR_EDR:
- return start_inquiry(index, LENGTH_BR_INQ);
- case LE_ONLY:
- return start_scanning(index, TIMEOUT_LE_SCAN);
- default:
- return -EINVAL;
- }
-}
-
-static int hciops_stop_discovery(int index)
-{
- struct dev_info *dev = &devs[index];
-
- DBG("index %d", index);
-
- switch (dev->discov_state) {
- case DISCOV_INQ:
- return hciops_stop_inquiry(index);
- case DISCOV_SCAN:
- return hciops_stop_scanning(index);
- case DISCOV_NAMES:
- cancel_resolve_name(index);
- default:
- return -EINVAL;
- }
-}
-
-static int hciops_set_fast_connectable(int index, gboolean enable)
-{
- struct dev_info *dev = &devs[index];
- write_page_activity_cp cp;
- uint8_t type;
-
- DBG("hci%d enable %d", index, enable);
-
- if (enable) {
- type = PAGE_SCAN_TYPE_INTERLACED;
- cp.interval = 0x0024; /* 22.5 msec page scan interval */
- } else {
- type = PAGE_SCAN_TYPE_STANDARD; /* default */
- cp.interval = 0x0800; /* default 1.28 sec page scan */
- }
-
- cp.window = 0x0012; /* default 11.25 msec page scan window */
-
- if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_PAGE_ACTIVITY,
- WRITE_PAGE_ACTIVITY_CP_SIZE, &cp) < 0)
- return -errno;
- else if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
- OCF_WRITE_PAGE_SCAN_TYPE, 1, &type) < 0)
- return -errno;
-
- return 0;
-}
-
-static int hciops_read_clock(int index, bdaddr_t *bdaddr, int which,
- int timeout, uint32_t *clock,
- uint16_t *accuracy)
-{
- struct dev_info *dev = &devs[index];
- uint16_t handle = 0;
- char addr[18];
- int ret;
-
- ba2str(bdaddr, addr);
- DBG("hci%d addr %s which %d timeout %d", index, addr, which, timeout);
-
- ret = get_handle(index, bdaddr, &handle);
- if (ret < 0)
- return ret;
-
- if (hci_read_clock(dev->sk, htobs(handle), which, clock, accuracy,
- timeout) < 0)
- return -errno;
-
- return 0;
-}
-
-static int hciops_read_bdaddr(int index, bdaddr_t *bdaddr)
-{
- struct dev_info *dev = &devs[index];
-
- DBG("hci%d", index);
-
- bacpy(bdaddr, &dev->bdaddr);
-
- return 0;
-}
-
-static int hciops_block_device(int index, bdaddr_t *bdaddr,
- uint8_t bdaddr_type)
-{
- struct dev_info *dev = &devs[index];
- char addr[18];
-
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s", index, addr);
-
- if (ioctl(dev->sk, HCIBLOCKADDR, bdaddr) < 0)
- return -errno;
-
- return 0;
-}
-
-static int hciops_unblock_device(int index, bdaddr_t *bdaddr,
- uint8_t bdaddr_type)
-{
- struct dev_info *dev = &devs[index];
- char addr[18];
-
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s", index, addr);
-
- if (ioctl(dev->sk, HCIUNBLOCKADDR, bdaddr) < 0)
- return -errno;
-
- return 0;
-}
-
-static int hciops_get_conn_list(int index, GSList **conns)
-{
- struct dev_info *dev = &devs[index];
- GSList *l;
-
- DBG("hci%d", index);
-
- *conns = NULL;
-
- for (l = dev->connections; l != NULL; l = g_slist_next(l)) {
- struct bt_conn *conn = l->data;
-
- *conns = g_slist_append(*conns,
- g_memdup(&conn->bdaddr, sizeof(bdaddr_t)));
- }
-
- return 0;
-}
-
-static int hciops_disconnect(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type)
-{
- DBG("hci%d", index);
-
- return disconnect_addr(index, bdaddr, HCI_OE_USER_ENDED_CONNECTION);
-}
-
-static int hciops_remove_bonding(int index, bdaddr_t *bdaddr,
- uint8_t bdaddr_type)
-{
- struct dev_info *dev = &devs[index];
- delete_stored_link_key_cp cp;
- GSList *match;
- char addr[18];
-
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s", index, addr);
-
- match = g_slist_find_custom(dev->keys, bdaddr, (GCompareFunc) bacmp);
- if (match) {
- g_free(match->data);
- dev->keys = g_slist_delete_link(dev->keys, match);
- }
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, bdaddr);
-
- /* Delete the link key from the Bluetooth chip */
- if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_DELETE_STORED_LINK_KEY,
- DELETE_STORED_LINK_KEY_CP_SIZE, &cp) < 0)
- return -errno;
-
- return 0;
-}
-
-static int hciops_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin,
- size_t pin_len)
-{
- struct dev_info *dev = &devs[index];
- char addr[18];
- int err;
-
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s", index, addr);
-
- if (pin) {
- pin_code_reply_cp pr;
-
- dev->pin_length = pin_len;
-
- memset(&pr, 0, sizeof(pr));
- bacpy(&pr.bdaddr, bdaddr);
- memcpy(pr.pin_code, pin, pin_len);
- pr.pin_len = pin_len;
- err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
- OCF_PIN_CODE_REPLY,
- PIN_CODE_REPLY_CP_SIZE, &pr);
- } else
- err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
- OCF_PIN_CODE_NEG_REPLY, 6, bdaddr);
-
- if (err < 0)
- err = -errno;
-
- return err;
-}
-
-static int hciops_passkey_reply(int index, bdaddr_t *bdaddr,
- uint8_t bdaddr_type, uint32_t passkey)
-{
- struct dev_info *dev = &devs[index];
- char addr[18];
- int err;
-
- ba2str(bdaddr, addr);
- DBG("hci%d dba %s", index, addr);
-
- if (passkey != INVALID_PASSKEY) {
- user_passkey_reply_cp cp;
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.bdaddr, bdaddr);
- cp.passkey = passkey;
-
- err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
- OCF_USER_PASSKEY_REPLY,
- USER_PASSKEY_REPLY_CP_SIZE, &cp);
- } else
- err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
- OCF_USER_PASSKEY_NEG_REPLY, 6, bdaddr);
-
- if (err < 0)
- err = -errno;
-
- return err;
-}
-
-static uint8_t generate_service_class(int index)
-{
- struct dev_info *dev = &devs[index];
- GSList *l;
- uint8_t val = 0;
-
- for (l = dev->uuids; l != NULL; l = g_slist_next(l)) {
- struct uuid_info *uuid = l->data;
-
- val |= uuid->svc_hint;
- }
-
- return val;
-}
-
-static int update_service_classes(int index)
-{
- struct dev_info *dev = &devs[index];
- uint8_t value;
- int err;
-
- value = generate_service_class(index);
-
- DBG("hci%d value %u", index, value);
-
- /* Update only the service class, keep the limited bit,
- * major/minor class bits intact */
- dev->wanted_cod &= 0x00ffff;
- dev->wanted_cod |= (value << 16);
-
- /* If the cache is enabled or an existing CoD write is in progress
- * just bail out */
- if (dev->cache_enable || dev->pending_cod)
- return 0;
-
- /* If we already have the CoD we want, update EIR and return */
- if (dev->current_cod == dev->wanted_cod) {
- update_ext_inquiry_response(index);
- return 0;
- }
-
- DBG("Changing service classes to 0x%06x", dev->wanted_cod);
-
- err = write_class(index, dev->wanted_cod);
- if (err < 0)
- error("Adapter class update failed: %s (%d)",
- strerror(-err), -err);
-
- return err;
-}
-
-static int hciops_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
-{
- struct dev_info *dev = &devs[index];
- struct uuid_info *info;
-
- DBG("hci%d", index);
-
- info = g_new0(struct uuid_info, 1);
- memcpy(&info->uuid, uuid, sizeof(*uuid));
- info->svc_hint = svc_hint;
-
- dev->uuids = g_slist_append(dev->uuids, info);
-
- return update_service_classes(index);
-}
-
-static int hciops_remove_uuid(int index, uuid_t *uuid)
-{
- struct dev_info *dev = &devs[index];
- GSList *match;
-
- match = g_slist_find_custom(dev->uuids, uuid, sdp_uuid_cmp);
- if (match) {
- g_free(match->data);
- dev->uuids = g_slist_delete_link(dev->uuids, match);
- }
-
- DBG("hci%d", index);
-
- return update_service_classes(index);
-}
-
-static int hciops_disable_cod_cache(int index)
-{
- struct dev_info *dev = &devs[index];
-
- DBG("hci%d cache_enable %d", index, dev->cache_enable);
-
- if (!dev->cache_enable)
- return 0;
-
- DBG("hci%d current_cod 0x%06x wanted_cod 0x%06x", index,
- dev->current_cod, dev->wanted_cod);
-
- /* Disable and flush svc cache. All successive service class
- * updates * will be written to the device */
- dev->cache_enable = FALSE;
-
- if (dev->current_cod == dev->wanted_cod) {
- update_ext_inquiry_response(index);
- return 0;
- }
-
- return write_class(index, dev->wanted_cod);
-}
-
-static int hciops_restore_powered(int index)
-{
- struct dev_info *dev = &devs[index];
-
- if (!dev->already_up && dev->up)
- return hciops_power_off(index);
-
- return 0;
-}
-
-static int hciops_load_keys(int index, GSList *keys, gboolean debug_keys)
-{
- struct dev_info *dev = &devs[index];
- GSList *l;
-
- DBG("hci%d keys %d debug_keys %d", index, g_slist_length(keys),
- debug_keys);
-
- if (dev->keys != NULL)
- return -EEXIST;
-
- for (l = keys; l; l = l->next) {
- struct link_key_info *orig, *dup;
-
- orig = l->data;
-
- dup = g_memdup(orig, sizeof(*orig));
-
- dev->keys = g_slist_prepend(dev->keys, dup);
- }
-
- dev->debug_keys = debug_keys;
-
- return 0;
-}
-
-static int hciops_set_io_capability(int index, uint8_t io_capability)
-{
- struct dev_info *dev = &devs[index];
-
- /* hciops is not to be used for SMP pairing for LE devices. So
- * change the IO capability from KeyboardDisplay to DisplayYesNo
- * in case it is set. */
- dev->io_capability = (io_capability == 0x04) ? 0x01 : io_capability;
-
- return 0;
-}
-
-static int request_authentication(int index, bdaddr_t *bdaddr)
-{
- struct dev_info *dev = &devs[index];
- auth_requested_cp cp;
- uint16_t handle;
- int err;
-
- DBG("hci%d", index);
-
- err = get_handle(index, bdaddr, &handle);
- if (err < 0)
- return err;
-
- memset(&cp, 0, sizeof(cp));
- cp.handle = htobs(handle);
-
- if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
- AUTH_REQUESTED_CP_SIZE, &cp) < 0)
- return -errno;
-
- return 0;
-}
-
-static void bonding_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
-{
- struct bt_conn *conn = user_data;
- struct dev_info *dev = conn->dev;
-
- if (!conn->io) {
- if (!err)
- g_io_channel_shutdown(io, TRUE, NULL);
- return;
- }
-
- if (err)
- /* Wait proper error to be propagated by bonding complete */
- return;
-
- if (request_authentication(dev->id, &conn->bdaddr) < 0)
- goto failed;
-
- return;
-
-failed:
- bonding_complete(dev, conn, HCI_UNSPECIFIED_ERROR);
-}
-
-static int hciops_create_bonding(int index, bdaddr_t *bdaddr,
- uint8_t bdaddr_type, uint8_t io_cap)
-{
- struct dev_info *dev = &devs[index];
- BtIOSecLevel sec_level;
- struct bt_conn *conn;
- GError *err = NULL;
-
- conn = get_connection(dev, bdaddr);
-
- if (conn->io != NULL)
- return -EBUSY;
-
- /* hciops is not to be used for SMP pairing for LE devices. So
- * change the IO capability from KeyboardDisplay to DisplayYesNo
- * in case it is set. */
- conn->loc_cap = (io_cap == 0x04 ? 0x01 : io_cap);
-
- /* If our IO capability is NoInputNoOutput use medium security
- * level (i.e. don't require MITM protection) else use high
- * security level */
- if (io_cap == 0x03)
- sec_level = BT_IO_SEC_MEDIUM;
- else
- sec_level = BT_IO_SEC_HIGH;
-
- conn->io = bt_io_connect(BT_IO_L2RAW, bonding_connect_cb, conn,
- NULL, &err,
- BT_IO_OPT_SOURCE_BDADDR, &dev->bdaddr,
- BT_IO_OPT_DEST_BDADDR, bdaddr,
- BT_IO_OPT_SEC_LEVEL, sec_level,
- BT_IO_OPT_INVALID);
- if (conn->io == NULL) {
- error("bt_io_connect: %s", err->message);
- g_error_free(err);
- return -EIO;
- }
-
- conn->bonding_initiator = TRUE;
-
- return 0;
-}
-
-static int hciops_cancel_bonding(int index, bdaddr_t *bdaddr)
-{
- struct dev_info *dev = &devs[index];
- struct bt_conn *conn;
-
- DBG("hci%d", index);
-
- conn = find_connection(dev, bdaddr);
- if (conn == NULL || conn->io == NULL)
- return -ENOTCONN;
-
- g_io_channel_shutdown(conn->io, TRUE, NULL);
- g_io_channel_unref(conn->io);
- conn->io = NULL;
-
- return 0;
-}
-
-static int hciops_read_local_oob_data(int index)
-{
- struct dev_info *dev = &devs[index];
-
- DBG("hci%d", index);
-
- if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA, 0, 0)
- < 0)
- return -errno;
-
- return 0;
-}
-
-static int hciops_add_remote_oob_data(int index, bdaddr_t *bdaddr,
- uint8_t *hash, uint8_t *randomizer)
-{
- char addr[18];
- struct dev_info *dev = &devs[index];
- GSList *match;
- struct oob_data *data;
-
- ba2str(bdaddr, addr);
- DBG("hci%d bdaddr %s", index, addr);
-
- match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
-
- if (match) {
- data = match->data;
- } else {
- data = g_new(struct oob_data, 1);
- bacpy(&data->bdaddr, bdaddr);
- dev->oob_data = g_slist_prepend(dev->oob_data, data);
- }
-
- memcpy(data->hash, hash, sizeof(data->hash));
- memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
-
- return 0;
-}
-
-static int hciops_remove_remote_oob_data(int index, bdaddr_t *bdaddr)
-{
- char addr[18];
- struct dev_info *dev = &devs[index];
- GSList *match;
-
- ba2str(bdaddr, addr);
- DBG("hci%d bdaddr %s", index, addr);
-
- match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
-
- if (!match)
- return -ENOENT;
-
- g_free(match->data);
- dev->oob_data = g_slist_delete_link(dev->oob_data, match);
-
- return 0;
-}
-
-static int hciops_confirm_name(int index, bdaddr_t *bdaddr,
- uint8_t bdaddr_type, gboolean name_known)
-{
- struct dev_info *info = &devs[index];
- struct found_dev *dev;
- GSList *match;
- char addr[18];
-
- ba2str(bdaddr, addr);
- DBG("hci%u %s name_known %u", index, addr, name_known);
-
- match = g_slist_find_custom(info->found_devs, bdaddr,
- found_dev_bda_cmp);
- if (match == NULL)
- return -ENOENT;
-
- dev = match->data;
-
- if (name_known) {
- dev->name_state = NAME_NOT_NEEDED;
- info->found_devs = g_slist_sort(info->found_devs,
- found_dev_rssi_cmp);
- return 0;
- }
-
- dev->name_state = NAME_NEEDED;
- info->found_devs = g_slist_remove_link(info->found_devs, match);
-
- match->next = info->need_name;
- info->need_name = match;
- info->need_name = g_slist_sort(info->need_name, found_dev_rssi_cmp);
-
- return 0;
-}
-
-static int hciops_load_ltks(int index, GSList *keys)
-{
- return -ENOSYS;
-}
-
-static struct btd_adapter_ops hci_ops = {
- .setup = hciops_setup,
- .cleanup = hciops_cleanup,
- .set_powered = hciops_set_powered,
- .set_discoverable = hciops_set_discoverable,
- .set_pairable = hciops_set_pairable,
- .start_discovery = hciops_start_discovery,
- .stop_discovery = hciops_stop_discovery,
- .set_name = hciops_set_name,
- .set_dev_class = hciops_set_dev_class,
- .set_fast_connectable = hciops_set_fast_connectable,
- .read_clock = hciops_read_clock,
- .read_bdaddr = hciops_read_bdaddr,
- .block_device = hciops_block_device,
- .unblock_device = hciops_unblock_device,
- .get_conn_list = hciops_get_conn_list,
- .disconnect = hciops_disconnect,
- .remove_bonding = hciops_remove_bonding,
- .pincode_reply = hciops_pincode_reply,
- .confirm_reply = hciops_confirm_reply,
- .passkey_reply = hciops_passkey_reply,
- .encrypt_link = hciops_encrypt_link,
- .set_did = hciops_set_did,
- .add_uuid = hciops_add_uuid,
- .remove_uuid = hciops_remove_uuid,
- .disable_cod_cache = hciops_disable_cod_cache,
- .restore_powered = hciops_restore_powered,
- .load_keys = hciops_load_keys,
- .set_io_capability = hciops_set_io_capability,
- .create_bonding = hciops_create_bonding,
- .cancel_bonding = hciops_cancel_bonding,
- .read_local_oob_data = hciops_read_local_oob_data,
- .add_remote_oob_data = hciops_add_remote_oob_data,
- .remove_remote_oob_data = hciops_remove_remote_oob_data,
- .confirm_name = hciops_confirm_name,
- .load_ltks = hciops_load_ltks,
-};
-
-static int hciops_init(void)
-{
- DBG("");
- return btd_register_adapter_ops(&hci_ops, FALSE);
-}
-
-static void hciops_exit(void)
-{
- DBG("");
- btd_adapter_cleanup_ops(&hci_ops);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(hciops, VERSION,
- BLUETOOTH_PLUGIN_PRIORITY_LOW, hciops_init, hciops_exit)
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 03/21] headset: remove deprecated DBus methods
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
2012-06-13 20:43 ` [PATCH 02/21] remove the hciops plugin Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-14 7:43 ` Chanyeol Park
2012-06-14 14:07 ` [PATCH -v2 " Gustavo Padovan
2012-06-13 20:43 ` [PATCH 04/21] sink: remove deprecated DBus method Gustavo Padovan
` (17 subsequent siblings)
19 siblings, 2 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
audio/headset.c | 151 -----------------------------------------------------
doc/audio-api.txt | 28 ----------
2 files changed, 179 deletions(-)
diff --git a/audio/headset.c b/audio/headset.c
index 729e4dc..3ce7eb9 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -1673,26 +1673,6 @@ static DBusMessage *hs_stop(DBusConnection *conn, DBusMessage *msg,
return reply;
}
-static DBusMessage *hs_is_playing(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- DBusMessage *reply;
- dbus_bool_t playing;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- playing = (hs->state == HEADSET_STATE_PLAYING);
-
- dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
static DBusMessage *hs_disconnect(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -1816,95 +1796,6 @@ static DBusMessage *hs_cancel_call(DBusConnection *conn,
return reply;
}
-static DBusMessage *hs_play(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- int err;
-
- if (sco_hci) {
- error("Refusing Headset.Play() because SCO HCI routing "
- "is enabled");
- return btd_error_not_available(msg);
- }
-
- switch (hs->state) {
- case HEADSET_STATE_DISCONNECTED:
- case HEADSET_STATE_CONNECTING:
- return btd_error_not_connected(msg);
- case HEADSET_STATE_PLAY_IN_PROGRESS:
- if (hs->pending && hs->pending->msg == NULL) {
- hs->pending->msg = dbus_message_ref(msg);
- return NULL;
- }
- return btd_error_busy(msg);
- case HEADSET_STATE_PLAYING:
- return btd_error_already_connected(msg);
- case HEADSET_STATE_CONNECTED:
- default:
- break;
- }
-
- err = sco_connect(device, NULL, NULL, NULL);
- if (err < 0)
- return btd_error_failed(msg, strerror(-err));
-
- hs->pending->msg = dbus_message_ref(msg);
-
- return NULL;
-}
-
-static DBusMessage *hs_get_speaker_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- DBusMessage *reply;
- dbus_uint16_t gain;
-
- if (hs->state < HEADSET_STATE_CONNECTED)
- return btd_error_not_available(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- gain = (dbus_uint16_t) slc->sp_gain;
-
- dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
-static DBusMessage *hs_get_mic_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- DBusMessage *reply;
- dbus_uint16_t gain;
-
- if (hs->state < HEADSET_STATE_CONNECTED || slc == NULL)
- return btd_error_not_available(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- gain = (dbus_uint16_t) slc->mic_gain;
-
- dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
static DBusMessage *hs_set_gain(DBusConnection *conn,
DBusMessage *msg,
void *data, uint16_t gain,
@@ -1937,32 +1828,6 @@ static DBusMessage *hs_set_gain(DBusConnection *conn,
return reply;
}
-static DBusMessage *hs_set_speaker_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- uint16_t gain;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID))
- return NULL;
-
- return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_SPEAKER);
-}
-
-static DBusMessage *hs_set_mic_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- uint16_t gain;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID))
- return NULL;
-
- return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_MICROPHONE);
-}
-
static DBusMessage *hs_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -2065,23 +1930,7 @@ static const GDBusMethodTable headset_methods[] = {
hs_is_connected) },
{ GDBUS_METHOD("IndicateCall", NULL, NULL, hs_ring) },
{ GDBUS_METHOD("CancelCall", NULL, NULL, hs_cancel_call) },
- { GDBUS_DEPRECATED_ASYNC_METHOD("Play", NULL, NULL, hs_play) },
{ GDBUS_METHOD("Stop", NULL, NULL, hs_stop) },
- { GDBUS_DEPRECATED_METHOD("IsPlaying",
- NULL, GDBUS_ARGS({ "playing", "b" }),
- hs_is_playing) },
- { GDBUS_DEPRECATED_METHOD("GetSpeakerGain",
- NULL, GDBUS_ARGS({ "gain", "q" }),
- hs_get_speaker_gain) },
- { GDBUS_DEPRECATED_METHOD("GetMicrophoneGain",
- NULL, GDBUS_ARGS({ "gain", "q" }),
- hs_get_mic_gain) },
- { GDBUS_DEPRECATED_METHOD("SetSpeakerGain",
- GDBUS_ARGS({ "gain", "q" }), NULL,
- hs_set_speaker_gain) },
- { GDBUS_DEPRECATED_METHOD("SetMicrophoneGain",
- GDBUS_ARGS({ "gain", "q" }), NULL,
- hs_set_mic_gain) },
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
hs_get_properties) },
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index 02291fd..dc5c811 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -66,11 +66,6 @@ Methods void Connect()
Disconnect from the HSP/HFP service on the remote
device.
- boolean IsConnected() {deprecated}
-
- Returns TRUE if there is a active connection to the
- HSP/HFP connection on the remote device.
-
void IndicateCall()
Indicate an incoming call on the headset
@@ -89,29 +84,6 @@ Methods void Connect()
Close the audio connection.
- boolean IsPlaying() {deprecated}
-
- Returns true if an audio connection to the headset
- is active.
-
- uint16 GetSpeakerGain() {deprecated}
-
- Returns the current speaker gain if available,
- otherwise returns the error NotAvailable.
-
- uint16 GetMicrophoneGain() {deprecated}
-
- Returns the current microphone gain if available,
- otherwise returns the error NotAvailable.
-
- void SetSpeakerGain(uint16 gain) {deprecated}
-
- Changes the current speaker gain if possible.
-
- void SetMicrophoneGain(uint16 gain) {deprecated}
-
- Changes the current speaker gain if possible.
-
dict GetProperties()
Returns all properties for the interface. See the
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 04/21] sink: remove deprecated DBus method
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
2012-06-13 20:43 ` [PATCH 02/21] remove the hciops plugin Gustavo Padovan
2012-06-13 20:43 ` [PATCH 03/21] headset: remove deprecated DBus methods Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 05/21] adapter: remove deprecated ListDevices() method Gustavo Padovan
` (16 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
audio/sink.c | 24 ------------------------
doc/audio-api.txt | 5 -----
2 files changed, 29 deletions(-)
diff --git a/audio/sink.c b/audio/sink.c
index 6b21e47..3116fbe 100644
--- a/audio/sink.c
+++ b/audio/sink.c
@@ -494,27 +494,6 @@ static DBusMessage *sink_disconnect(DBusConnection *conn,
return NULL;
}
-static DBusMessage *sink_is_connected(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct sink *sink = device->sink;
- DBusMessage *reply;
- dbus_bool_t connected;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- connected = (sink->stream_state >= AVDTP_STATE_CONFIGURED);
-
- dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
static DBusMessage *sink_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -558,9 +537,6 @@ static DBusMessage *sink_get_properties(DBusConnection *conn,
static const GDBusMethodTable sink_methods[] = {
{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, sink_connect) },
{ GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, sink_disconnect) },
- { GDBUS_DEPRECATED_METHOD("IsConnected",
- NULL, GDBUS_ARGS({ "connected", "b" }),
- sink_is_connected) },
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
sink_get_properties) },
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index dc5c811..72294dd 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -193,11 +193,6 @@ Methods void Connect()
Disconnect from the remote device.
- boolean IsConnected() {deprecated}
-
- Returns TRUE if a stream is setup to a A2DP sink on
- the remote device.
-
dict GetProperties()
Returns all properties for the interface. See the
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 05/21] adapter: remove deprecated ListDevices() method
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (2 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 04/21] sink: remove deprecated DBus method Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 06/21] manager: remove deprecated ListAdapters() method Gustavo Padovan
` (15 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
doc/adapter-api.txt | 10 ----------
src/adapter.c | 35 -----------------------------------
2 files changed, 45 deletions(-)
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index dccb6bf..3eea23d 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -88,16 +88,6 @@ Methods dict GetProperties()
Possible Errors: org.bluez.Error.DoesNotExist
org.bluez.Error.InvalidArguments
- array{object} ListDevices() {deprecated}
-
- Returns list of device object paths.
- This method is deprecated, instead use the Devices
- Property to get the list of devices object paths.
-
- Possible errors: org.bluez.Error.InvalidArguments
- org.bluez.Error.Failed
- org.bluez.Error.OutOfMemory
-
object CreateDevice(string address)
Creates a new object path for a remote device. This
diff --git a/src/adapter.c b/src/adapter.c
index 6e04faf..3535cc4 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1307,38 +1307,6 @@ static DBusMessage *release_session(DBusConnection *conn,
return dbus_message_new_method_return(msg);
}
-static DBusMessage *list_devices(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct btd_adapter *adapter = data;
- DBusMessage *reply;
- GSList *l;
- DBusMessageIter iter;
- DBusMessageIter array_iter;
- const gchar *dev_path;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
-
- for (l = adapter->devices; l; l = l->next) {
- struct btd_device *device = l->data;
-
- dev_path = device_get_path(device);
-
- dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_OBJECT_PATH, &dev_path);
- }
-
- dbus_message_iter_close_container(&iter, &array_iter);
-
- return reply;
-}
-
static DBusMessage *cancel_device_creation(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -1662,9 +1630,6 @@ static const GDBusMethodTable adapter_methods[] = {
adapter_start_discovery) },
{ GDBUS_ASYNC_METHOD("StopDiscovery", NULL, NULL,
adapter_stop_discovery) },
- { GDBUS_DEPRECATED_METHOD("ListDevices",
- NULL, GDBUS_ARGS({ "devices", "ao" }),
- list_devices) },
{ GDBUS_ASYNC_METHOD("CreateDevice",
GDBUS_ARGS({ "address", "s" }),
GDBUS_ARGS({ "device", "o" }),
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 06/21] manager: remove deprecated ListAdapters() method
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (3 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 05/21] adapter: remove deprecated ListDevices() method Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 07/21] adapter: remove btd_adapter_encrypt_link() Gustavo Padovan
` (14 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
src/manager.c | 33 ---------------------------------
1 file changed, 33 deletions(-)
diff --git a/src/manager.c b/src/manager.c
index 385354d..d588995 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -130,36 +130,6 @@ done:
return reply;
}
-static DBusMessage *list_adapters(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- DBusMessageIter iter;
- DBusMessageIter array_iter;
- DBusMessage *reply;
- GSList *l;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- dbus_message_iter_init_append(reply, &iter);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
-
- for (l = adapters; l; l = l->next) {
- struct btd_adapter *adapter = l->data;
- const gchar *path = adapter_get_path(adapter);
-
- dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_OBJECT_PATH, &path);
- }
-
- dbus_message_iter_close_container(&iter, &array_iter);
-
- return reply;
-}
-
static DBusMessage *get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -207,9 +177,6 @@ static const GDBusMethodTable manager_methods[] = {
GDBUS_ARGS({ "pattern", "s" }),
GDBUS_ARGS({ "adapter", "o" }),
find_adapter) },
- { GDBUS_ASYNC_METHOD("ListAdapters",
- NULL, GDBUS_ARGS({ "adapters", "ao" }),
- list_adapters) },
{ }
};
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 07/21] adapter: remove btd_adapter_encrypt_link()
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (4 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 06/21] manager: remove deprecated ListAdapters() method Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 08/21] adapter_ops: remove disable_cod_cache Gustavo Padovan
` (13 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
After the removal of hciops this function is not necessary anymore, we now
use setsockopt to accomplish the encryption of the link.
---
input/device.c | 38 ++++++++++----------------------------
plugins/mgmtops.c | 12 ------------
src/adapter.c | 6 ------
src/adapter.h | 5 -----
4 files changed, 10 insertions(+), 51 deletions(-)
diff --git a/input/device.c b/input/device.c
index 0e3f4a9..8ed722b 100644
--- a/input/device.c
+++ b/input/device.c
@@ -643,22 +643,18 @@ static int hidp_add_connection(const struct input_device *idev,
/* Encryption is mandatory for keyboards */
if (req->subclass & 0x40) {
- struct btd_adapter *adapter = device_get_adapter(idev->device);
-
- err = btd_adapter_encrypt_link(adapter, (bdaddr_t *) &idev->dst,
- encrypt_completed, req);
- if (err == 0) {
- /* Waiting async encryption */
- return 0;
- }
-
- if (err == -ENOSYS)
- goto nosys;
-
- if (err != -EALREADY) {
- error("encrypt_link: %s (%d)", strerror(-err), -err);
+ if (!bt_io_set(iconn->intr_io, BT_IO_L2CAP, &gerr,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_INVALID)) {
+ error("btio: %s", gerr->message);
+ g_error_free(gerr);
+ err = -EFAULT;
goto cleanup;
}
+
+ iconn->req = req;
+ iconn->sec_watch = g_io_add_watch(iconn->intr_io, G_IO_OUT,
+ encrypt_notify, iconn);
}
err = ioctl_connadd(req);
@@ -668,20 +664,6 @@ cleanup:
g_free(req);
return err;
-
-nosys:
- if (!bt_io_set(iconn->intr_io, BT_IO_L2CAP, &gerr,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
- BT_IO_OPT_INVALID)) {
- error("btio: %s", gerr->message);
- g_error_free(gerr);
- goto cleanup;
- }
-
- iconn->req = req;
- iconn->sec_watch = g_io_add_watch(iconn->intr_io, G_IO_OUT,
- encrypt_notify, iconn);
- return 0;
}
static int is_connected(struct input_conn *iconn)
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index 16a97c9..f734edc 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -2157,17 +2157,6 @@ static int mgmt_unpair_device(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type)
return 0;
}
-static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
- gpointer user_data)
-{
- char addr[18];
-
- ba2str(dst, addr);
- DBG("index %d addr %s", index, addr);
-
- return -ENOSYS;
-}
-
static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
uint16_t version, uint16_t source)
{
@@ -2492,7 +2481,6 @@ static struct btd_adapter_ops mgmt_ops = {
.pincode_reply = mgmt_pincode_reply,
.confirm_reply = mgmt_confirm_reply,
.passkey_reply = mgmt_passkey_reply,
- .encrypt_link = mgmt_encrypt_link,
.set_did = mgmt_set_did,
.add_uuid = mgmt_add_uuid,
.remove_uuid = mgmt_remove_uuid,
diff --git a/src/adapter.c b/src/adapter.c
index 3535cc4..16070a8 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3478,12 +3478,6 @@ int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
passkey);
}
-int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
- bt_hci_result_t cb, gpointer user_data)
-{
- return adapter_ops->encrypt_link(adapter->dev_id, bdaddr, cb, user_data);
-}
-
int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor,
uint16_t product, uint16_t version,
uint16_t source)
diff --git a/src/adapter.h b/src/adapter.h
index b7ea62b..77d79c1 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -200,8 +200,6 @@ struct btd_adapter_ops {
gboolean success);
int (*passkey_reply) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
uint32_t passkey);
- int (*encrypt_link) (int index, bdaddr_t *bdaddr, bt_hci_result_t cb,
- gpointer user_data);
int (*set_did) (int index, uint16_t vendor, uint16_t product,
uint16_t version, uint16_t source);
int (*add_uuid) (int index, uuid_t *uuid, uint8_t svc_hint);
@@ -261,9 +259,6 @@ int btd_adapter_confirm_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
uint8_t bdaddr_type, uint32_t passkey);
-int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
- bt_hci_result_t cb, gpointer user_data);
-
int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor,
uint16_t product, uint16_t version,
uint16_t source);
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 08/21] adapter_ops: remove disable_cod_cache
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (5 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 07/21] adapter: remove btd_adapter_encrypt_link() Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 09/21] manager: remove unused manager_add_adapter() Gustavo Padovan
` (12 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
mgmt handles the cache automatically.
---
plugins/mgmtops.c | 9 ---------
src/adapter.c | 2 --
src/adapter.h | 1 -
3 files changed, 12 deletions(-)
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index f734edc..7c77be8 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -2183,14 +2183,6 @@ static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
return 0;
}
-static int mgmt_disable_cod_cache(int index)
-{
- DBG("index %d", index);
-
- /* The cache control is handled automatically for mgmt */
- return 0;
-}
-
static int mgmt_restore_powered(int index)
{
DBG("index %d", index);
@@ -2484,7 +2476,6 @@ static struct btd_adapter_ops mgmt_ops = {
.set_did = mgmt_set_did,
.add_uuid = mgmt_add_uuid,
.remove_uuid = mgmt_remove_uuid,
- .disable_cod_cache = mgmt_disable_cod_cache,
.restore_powered = mgmt_restore_powered,
.load_keys = mgmt_load_link_keys,
.set_io_capability = mgmt_set_io_capability,
diff --git a/src/adapter.c b/src/adapter.c
index 16070a8..a82029a 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2188,8 +2188,6 @@ void btd_adapter_start(struct btd_adapter *adapter)
call_adapter_powered_callbacks(adapter, TRUE);
- adapter_ops->disable_cod_cache(adapter->dev_id);
-
info("Adapter %s has been enabled", adapter->path);
}
diff --git a/src/adapter.h b/src/adapter.h
index 77d79c1..4c39a7b 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -204,7 +204,6 @@ struct btd_adapter_ops {
uint16_t version, uint16_t source);
int (*add_uuid) (int index, uuid_t *uuid, uint8_t svc_hint);
int (*remove_uuid) (int index, uuid_t *uuid);
- int (*disable_cod_cache) (int index);
int (*restore_powered) (int index);
int (*load_keys) (int index, GSList *keys, gboolean debug_keys);
int (*set_io_capability) (int index, uint8_t io_capability);
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 09/21] manager: remove unused manager_add_adapter()
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (6 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 08/21] adapter_ops: remove disable_cod_cache Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 10/21] adapter: make restore powered work again Gustavo Padovan
` (11 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
src/manager.c | 12 ------------
src/manager.h | 1 -
2 files changed, 13 deletions(-)
diff --git a/src/manager.c b/src/manager.c
index d588995..4a39461 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -344,18 +344,6 @@ GSList *manager_get_adapters(void)
return adapters;
}
-void manager_add_adapter(const char *path)
-{
- g_dbus_emit_signal(connection, "/",
- MANAGER_INTERFACE, "AdapterAdded",
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
-
- manager_update_adapters();
-
- btd_stop_exit_timer();
-}
-
struct btd_adapter *btd_manager_register_adapter(int id, gboolean up)
{
struct btd_adapter *adapter;
diff --git a/src/manager.h b/src/manager.h
index 264cd25..f3c100e 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -40,4 +40,3 @@ void manager_foreach_adapter(adapter_cb func, gpointer user_data);
GSList *manager_get_adapters(void);
struct btd_adapter *btd_manager_register_adapter(int id, gboolean up);
int btd_manager_unregister_adapter(int id);
-void manager_add_adapter(const char *path);
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 10/21] adapter: make restore powered work again
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (7 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 09/21] manager: remove unused manager_add_adapter() Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 11/21] serial: remove SerialProxy interface Gustavo Padovan
` (10 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
differently from hciops mgmtops had no support to restore the powered of a
adapter. We now do this directly inside adapter_remove()
---
plugins/mgmtops.c | 7 -------
src/adapter.c | 5 ++++-
src/adapter.h | 1 -
3 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index 7c77be8..c060ada 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -2183,12 +2183,6 @@ static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
return 0;
}
-static int mgmt_restore_powered(int index)
-{
- DBG("index %d", index);
- return -ENOSYS;
-}
-
static int mgmt_load_link_keys(int index, GSList *keys, gboolean debug_keys)
{
char *buf;
@@ -2476,7 +2470,6 @@ static struct btd_adapter_ops mgmt_ops = {
.set_did = mgmt_set_did,
.add_uuid = mgmt_add_uuid,
.remove_uuid = mgmt_remove_uuid,
- .restore_powered = mgmt_restore_powered,
.load_keys = mgmt_load_link_keys,
.set_io_capability = mgmt_set_io_capability,
.create_bonding = mgmt_create_bonding,
diff --git a/src/adapter.c b/src/adapter.c
index a82029a..af6c003 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -109,6 +109,7 @@ struct service_auth {
struct btd_adapter {
uint16_t dev_id;
gboolean up;
+ gboolean already_up;
char *path; /* adapter object path */
bdaddr_t bdaddr; /* adapter Bluetooth Address */
uint32_t dev_class; /* Class of Device */
@@ -2389,6 +2390,7 @@ void btd_adapter_unref(struct btd_adapter *adapter)
gboolean adapter_init(struct btd_adapter *adapter, gboolean up)
{
adapter->up = up;
+ adapter->already_up = up;
adapter->allow_name_changes = TRUE;
@@ -2469,7 +2471,8 @@ void adapter_remove(struct btd_adapter *adapter)
g_slist_free(adapter->pin_callbacks);
/* Return adapter to down state if it was not up on init */
- adapter_ops->restore_powered(adapter->dev_id);
+ if (!adapter->already_up && adapter->up)
+ adapter_ops->set_powered(adapter->dev_id, FALSE);
}
uint16_t adapter_get_dev_id(struct btd_adapter *adapter)
diff --git a/src/adapter.h b/src/adapter.h
index 4c39a7b..73cd770 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -204,7 +204,6 @@ struct btd_adapter_ops {
uint16_t version, uint16_t source);
int (*add_uuid) (int index, uuid_t *uuid, uint8_t svc_hint);
int (*remove_uuid) (int index, uuid_t *uuid);
- int (*restore_powered) (int index);
int (*load_keys) (int index, GSList *keys, gboolean debug_keys);
int (*set_io_capability) (int index, uint8_t io_capability);
int (*create_bonding) (int index, bdaddr_t *bdaddr,
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 11/21] serial: remove SerialProxy interface
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (8 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 10/21] adapter: make restore powered work again Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 12/21] serial: remove unneeded headers include Gustavo Padovan
` (9 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
Makefile.am | 1 -
doc/serial-api.txt | 106 -----
serial/manager.c | 26 --
serial/proxy.c | 1269 ----------------------------------------------------
serial/proxy.h | 25 --
5 files changed, 1427 deletions(-)
delete mode 100644 serial/proxy.c
delete mode 100644 serial/proxy.h
diff --git a/Makefile.am b/Makefile.am
index 8c9ff3a..6dc1415 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -192,7 +192,6 @@ if SERIALPLUGIN
builtin_modules += serial
builtin_sources += serial/main.c \
serial/manager.h serial/manager.c \
- serial/proxy.h serial/proxy.c \
serial/port.h serial/port.c
endif
diff --git a/doc/serial-api.txt b/doc/serial-api.txt
index 0bdbdcd..42afe3d 100644
--- a/doc/serial-api.txt
+++ b/doc/serial-api.txt
@@ -55,109 +55,3 @@ Methods fd ConnectFD(string pattern) [experimental]
Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.DoesNotExist
-
-Serial Proxy Manager hierarchy [experimental]
-=============================================
-
-Service org.bluez
-Interface org.bluez.SerialProxyManager
-Object path [variable prefix]/{hci0,hci1,...}
-
-Methods array{string} ListProxies()
-
- Returns an array of the object path strings of
- all the proxies created for the adapter.
-
- string CreateProxy(string pattern, string address)
-
- Possible patterns: UUID 128 bit as string
- Profile short names, e.g: spp, dun
- RFCOMM channel as string, 1-30
-
- Address is the path to the TTY or Unix socket to be used.
- Only one proxy per address (TTY or Unix socket)
- is allowed.
-
- The object path of created proxy is returned.
- On success this will emit a ProxyCreated signal.
-
- Possible Errors: org.bluez.Error.InvalidArguments
- org.bluez.Error.AlreadyExists
- org.bluez.Error.Failed
-
- void RemoveProxy(string path)
-
- This removes the proxy object at the given path.
- On success this will emit a ProxyRemoved signal.
-
- Possible Errors: org.bluez.Error.DoesNotExist
- org.bluez.Error.NotAuthorized
-
-Signals ProxyCreated(string path)
-
- This signal indicates a proxy was created.
- Parameter is object path of created proxy.
-
- ProxyRemoved(string path)
-
- This signal indicates a proxy was removed.
- Parameter is object path of removed proxy.
-
-Serial Proxy hierarchy [experimental]
-=====================================
-
-Service org.bluez
-Interface org.bluez.SerialProxy
-Object path [variable prefix]/{hci0,hci1,...}/{proxy0,proxy1,...}
-
-Methods void Enable()
-
- Starts to listen to the TTY or Unix socket, allocates
- a RFCOMM channel and add record to the server.
-
- Possible errors: org.bluez.Error.Failed
-
- void Disable()
-
- Stops to listen to the TTY or Unix socket, shutdown
- the RFCOMM channel allocated for the proxy, and remove
- record from the server.
-
- Possible errors: org.bluez.Error.Failed
-
- dict GetInfo()
-
- Returns all properties for the proxy. See the
- properties section for available properties.
-
- void SetSerialParameters(string rate, uint8 data, uint8 stop,
- string parity)
-
- Configures serial communication setting baud rate,
- data bits, stop bits and parity.
-
- Doesn't allow change TTY settings if it is open.
-
- Possible errors: org.bluez.Error.InvalidArguments
- org.bluez.Error.NotAuthorized
-
-Properties string uuid [readonly]
-
- 128-bit UUID that represents the available remote service.
-
- string address [readonly]
-
- Address is the path to the TTY or Unix socket name used,
- set when the proxy was created.
-
- uint8 channel [readonly]
-
- RFCOMM channel.
-
- boolean enabled [readonly]
-
- Indicates if the proxy is currently enabled.
-
- boolean connected [readonly]
-
- Indicates if the proxy is currently connected.
diff --git a/serial/manager.c b/serial/manager.c
index 438ba6c..a84ce03 100644
--- a/serial/manager.c
+++ b/serial/manager.c
@@ -58,7 +58,6 @@
#include "error.h"
#include "port.h"
-#include "proxy.h"
#include "storage.h"
#include "manager.h"
#include "sdpd.h"
@@ -131,35 +130,10 @@ static struct btd_device_driver serial_port_driver = {
.remove = port_remove,
};
-static int proxy_probe(struct btd_adapter *adapter)
-{
- const char *path = adapter_get_path(adapter);
-
- DBG("path %s", path);
-
- return proxy_register(connection, adapter);
-}
-
-static void proxy_remove(struct btd_adapter *adapter)
-{
- const char *path = adapter_get_path(adapter);
-
- DBG("path %s", path);
-
- proxy_unregister(adapter);
-}
-
-static struct btd_adapter_driver serial_proxy_driver = {
- .name = "serial-proxy",
- .probe = proxy_probe,
- .remove = proxy_remove,
-};
-
int serial_manager_init(DBusConnection *conn)
{
connection = dbus_connection_ref(conn);
- btd_register_adapter_driver(&serial_proxy_driver);
btd_register_device_driver(&serial_port_driver);
return 0;
diff --git a/serial/proxy.c b/serial/proxy.c
deleted file mode 100644
index dd38317..0000000
--- a/serial/proxy.c
+++ /dev/null
@@ -1,1269 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/rfcomm.h>
-
-#include <glib.h>
-#include <gdbus.h>
-
-#include "../src/dbus-common.h"
-#include "../src/adapter.h"
-
-#include "log.h"
-
-#include "error.h"
-#include "sdpd.h"
-#include "glib-helper.h"
-#include "btio.h"
-#include "proxy.h"
-
-#define SERIAL_PROXY_INTERFACE "org.bluez.SerialProxy"
-#define SERIAL_MANAGER_INTERFACE "org.bluez.SerialProxyManager"
-#define BUF_SIZE 1024
-
-typedef enum {
- TTY_PROXY,
- UNIX_SOCKET_PROXY,
- TCP_SOCKET_PROXY,
- UNKNOWN_PROXY_TYPE = 0xFF
-} proxy_type_t;
-
-struct serial_adapter {
- struct btd_adapter *btd_adapter; /* Adapter pointer */
- DBusConnection *conn; /* Adapter connection */
- GSList *proxies; /* Proxies list */
-};
-
-struct serial_proxy {
- bdaddr_t src; /* Local address */
- bdaddr_t dst; /* Remote address */
- char *path; /* Proxy path */
- char *uuid128; /* UUID 128 */
- char *address; /* TTY or Unix socket name */
- char *owner; /* Application bus name */
- guint watch; /* Application watch */
- short int port; /* TCP port */
- proxy_type_t type; /* TTY or Unix socket */
- struct termios sys_ti; /* Default TTY setting */
- struct termios proxy_ti; /* Proxy TTY settings */
- uint8_t channel; /* RFCOMM channel */
- uint32_t record_id; /* Service record id */
- GIOChannel *io; /* Server listen */
- GIOChannel *rfcomm; /* Remote RFCOMM channel*/
- GIOChannel *local; /* Local channel: TTY or Unix socket */
- struct serial_adapter *adapter; /* Adapter pointer */
-};
-
-static GSList *adapters = NULL;
-static int sk_counter = 0;
-
-static void disable_proxy(struct serial_proxy *prx)
-{
- if (prx->rfcomm) {
- g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
- g_io_channel_unref(prx->rfcomm);
- prx->rfcomm = NULL;
- }
-
- if (prx->local) {
- g_io_channel_shutdown(prx->local, TRUE, NULL);
- g_io_channel_unref(prx->local);
- prx->local = NULL;
- }
-
- remove_record_from_server(prx->record_id);
- prx->record_id = 0;
-
- g_io_channel_unref(prx->io);
- prx->io = NULL;
-}
-
-static void proxy_free(struct serial_proxy *prx)
-{
- g_free(prx->owner);
- g_free(prx->path);
- g_free(prx->address);
- g_free(prx->uuid128);
- g_free(prx);
-}
-
-static sdp_record_t *proxy_record_new(const char *uuid128, uint8_t channel)
-{
- sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
- uuid_t uuid, root_uuid, l2cap, rfcomm;
- sdp_profile_desc_t profile;
- sdp_record_t *record;
- sdp_data_t *ch;
-
- record = sdp_record_alloc();
- if (!record)
- return NULL;
-
- sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
- root = sdp_list_append(NULL, &root_uuid);
- sdp_set_browse_groups(record, root);
- sdp_list_free(root, NULL);
-
- bt_string2uuid(&uuid, uuid128);
- sdp_uuid128_to_uuid(&uuid);
- svclass_id = sdp_list_append(NULL, &uuid);
- sdp_set_service_classes(record, svclass_id);
- sdp_list_free(svclass_id, NULL);
-
- sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
- profile.version = 0x0100;
- profiles = sdp_list_append(NULL, &profile);
- sdp_set_profile_descs(record, profiles);
- sdp_list_free(profiles, NULL);
-
- sdp_uuid16_create(&l2cap, L2CAP_UUID);
- proto[0] = sdp_list_append(NULL, &l2cap);
- apseq = sdp_list_append(NULL, proto[0]);
-
- sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
- proto[1] = sdp_list_append(NULL, &rfcomm);
- ch = sdp_data_alloc(SDP_UINT8, &channel);
- proto[1] = sdp_list_append(proto[1], ch);
- apseq = sdp_list_append(apseq, proto[1]);
-
- aproto = sdp_list_append(NULL, apseq);
- sdp_set_access_protos(record, aproto);
-
- sdp_add_lang_attr(record);
-
- sdp_set_info_attr(record, "Serial Proxy", NULL, "Serial Proxy");
-
- sdp_data_free(ch);
- sdp_list_free(proto[0], NULL);
- sdp_list_free(proto[1], NULL);
- sdp_list_free(apseq, NULL);
- sdp_list_free(aproto, NULL);
-
- return record;
-}
-
-static int channel_write(GIOChannel *chan, char *buf, size_t size)
-{
- size_t wbytes;
- ssize_t written;
- int fd;
-
- fd = g_io_channel_unix_get_fd(chan);
-
- wbytes = 0;
- while (wbytes < size) {
- written = write(fd, buf + wbytes, size - wbytes);
- if (written < 0)
- return -errno;
-
- wbytes += written;
- }
-
- return 0;
-}
-
-static gboolean forward_data(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
- char buf[BUF_SIZE];
- struct serial_proxy *prx = data;
- GIOChannel *dest;
- ssize_t rbytes;
- int fd, err;
-
- if (cond & G_IO_NVAL)
- return FALSE;
-
- dest = (chan == prx->rfcomm) ? prx->local : prx->rfcomm;
-
- fd = g_io_channel_unix_get_fd(chan);
-
- if (cond & (G_IO_HUP | G_IO_ERR)) {
- /* Try forward remaining data */
- do {
- rbytes = read(fd, buf, sizeof(buf));
- if (rbytes <= 0)
- break;
-
- err = channel_write(dest, buf, rbytes);
- } while (err == 0);
-
- g_io_channel_shutdown(prx->local, TRUE, NULL);
- g_io_channel_unref(prx->local);
- prx->local = NULL;
-
- g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
- g_io_channel_unref(prx->rfcomm);
- prx->rfcomm = NULL;
-
- return FALSE;
- }
-
- rbytes = read(fd, buf, sizeof(buf));
- if (rbytes < 0)
- return FALSE;
-
- err = channel_write(dest, buf, rbytes);
- if (err != 0)
- return FALSE;
-
- return TRUE;
-}
-
-static inline int unix_socket_connect(const char *address)
-{
- struct sockaddr_un addr;
- int err, sk;
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = PF_UNIX;
-
- if (strncmp("x00", address, 3) == 0) {
- /*
- * Abstract namespace: first byte NULL, x00
- * must be removed from the original address.
- */
- strncpy(addr.sun_path + 1, address + 3,
- sizeof(addr.sun_path) - 2);
- } else {
- /* Filesystem address */
- strncpy(addr.sun_path, address, sizeof(addr.sun_path) - 1);
- }
-
- /* Unix socket */
- sk = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sk < 0) {
- err = -errno;
- error("Unix socket(%s) create failed: %s(%d)",
- address, strerror(-err), -err);
- return err;
- }
-
- if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- err = -errno;
- error("Unix socket(%s) connect failed: %s(%d)",
- address, strerror(-err), -err);
- close(sk);
- return err;
- }
-
- return sk;
-}
-
-static int tcp_socket_connect(const char *address)
-{
- struct sockaddr_in addr;
- int err, sk, port;
-
- memset(&addr, 0, sizeof(addr));
-
- if (strncmp(address, "localhost", 9) != 0) {
- error("Address should have the form localhost:port.");
- return -1;
- }
- port = atoi(strchr(address, ':') + 1);
- if (port <= 0) {
- error("Invalid port '%d'.", port);
- return -1;
- }
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- addr.sin_port = htons(port);
-
- sk = socket(PF_INET, SOCK_STREAM, 0);
- if (sk < 0) {
- err = -errno;
- error("TCP socket(%s) create failed %s(%d)", address,
- strerror(-err), -err);
- return err;
- }
- if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- err = -errno;
- error("TCP socket(%s) connect failed: %s(%d)",
- address, strerror(-err), -err);
- close(sk);
- return err;
- }
- return sk;
-}
-
-static inline int tty_open(const char *tty, struct termios *ti)
-{
- int err, sk;
-
- sk = open(tty, O_RDWR | O_NOCTTY);
- if (sk < 0) {
- err = -errno;
- error("Can't open TTY %s: %s(%d)", tty, strerror(-err), -err);
- return err;
- }
-
- if (ti && tcsetattr(sk, TCSANOW, ti) < 0) {
- err = -errno;
- error("Can't change serial settings: %s(%d)",
- strerror(-err), -err);
- close(sk);
- return err;
- }
-
- return sk;
-}
-
-static void connect_event_cb(GIOChannel *chan, GError *conn_err, gpointer data)
-{
- struct serial_proxy *prx = data;
- int sk;
-
- if (conn_err) {
- error("%s", conn_err->message);
- goto drop;
- }
-
- /* Connect local */
- switch (prx->type) {
- case UNIX_SOCKET_PROXY:
- sk = unix_socket_connect(prx->address);
- break;
- case TTY_PROXY:
- sk = tty_open(prx->address, &prx->proxy_ti);
- break;
- case TCP_SOCKET_PROXY:
- sk = tcp_socket_connect(prx->address);
- break;
- default:
- sk = -1;
- }
-
- if (sk < 0)
- goto drop;
-
- prx->local = g_io_channel_unix_new(sk);
-
- g_io_add_watch(prx->rfcomm,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- forward_data, prx);
-
- g_io_add_watch(prx->local,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- forward_data, prx);
-
- return;
-
-drop:
- g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
- g_io_channel_unref(prx->rfcomm);
- prx->rfcomm = NULL;
-}
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
- struct serial_proxy *prx = user_data;
- GError *err = NULL;
-
- if (derr) {
- error("Access denied: %s", derr->message);
- goto reject;
- }
-
- if (!bt_io_accept(prx->rfcomm, connect_event_cb, prx, NULL,
- &err)) {
- error("bt_io_accept: %s", err->message);
- g_error_free(err);
- goto reject;
- }
-
- return;
-
-reject:
- g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
- g_io_channel_unref(prx->rfcomm);
- prx->rfcomm = NULL;
-}
-
-static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
-{
- struct serial_proxy *prx = user_data;
- int perr;
- char address[18];
- GError *err = NULL;
-
- bt_io_get(chan, BT_IO_RFCOMM, &err,
- BT_IO_OPT_DEST_BDADDR, &prx->dst,
- BT_IO_OPT_DEST, address,
- BT_IO_OPT_INVALID);
- if (err) {
- error("%s", err->message);
- g_error_free(err);
- goto drop;
- }
-
- if (prx->rfcomm) {
- error("Refusing connect from %s: Proxy already in use",
- address);
- goto drop;
- }
-
- DBG("Serial Proxy: incoming connect from %s", address);
-
- prx->rfcomm = g_io_channel_ref(chan);
-
- perr = btd_request_authorization(&prx->src, &prx->dst,
- prx->uuid128, auth_cb, prx);
- if (perr < 0) {
- error("Refusing connect from %s: %s (%d)", address,
- strerror(-perr), -perr);
- g_io_channel_unref(prx->rfcomm);
- prx->rfcomm = NULL;
- goto drop;
- }
-
- return;
-
-drop:
- g_io_channel_shutdown(chan, TRUE, NULL);
-}
-
-static int enable_proxy(struct serial_proxy *prx)
-{
- sdp_record_t *record;
- GError *gerr = NULL;
- int err;
-
- if (prx->io)
- return -EALREADY;
-
- /* Listen */
- prx->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event_cb, prx,
- NULL, &gerr,
- BT_IO_OPT_SOURCE_BDADDR, &prx->src,
- BT_IO_OPT_INVALID);
- if (!prx->io)
- goto failed;
-
- bt_io_get(prx->io, BT_IO_RFCOMM, &gerr,
- BT_IO_OPT_CHANNEL, &prx->channel,
- BT_IO_OPT_INVALID);
- if (gerr) {
- g_io_channel_unref(prx->io);
- prx->io = NULL;
- goto failed;
- }
-
- DBG("Allocated channel %d", prx->channel);
-
- g_io_channel_set_close_on_unref(prx->io, TRUE);
-
- record = proxy_record_new(prx->uuid128, prx->channel);
- if (!record) {
- g_io_channel_unref(prx->io);
- return -ENOMEM;
- }
-
- err = add_record_to_server(&prx->src, record);
- if (err < 0) {
- sdp_record_free(record);
- g_io_channel_unref(prx->io);
- return err;
- }
-
- prx->record_id = record->handle;
-
- return 0;
-
-failed:
- error("%s", gerr->message);
- g_error_free(gerr);
- return -EIO;
-
-}
-static DBusMessage *proxy_enable(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct serial_proxy *prx = data;
- int err;
-
- err = enable_proxy(prx);
- if (err < 0)
- return btd_error_failed(msg, strerror(-err));
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *proxy_disable(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct serial_proxy *prx = data;
-
- if (!prx->io)
- return btd_error_failed(msg, "Not enabled");
-
- /* Remove the watches and unregister the record */
- disable_proxy(prx);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *proxy_get_info(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct serial_proxy *prx = data;
- DBusMessage *reply;
- DBusMessageIter iter, dict;
- dbus_bool_t boolean;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- dbus_message_iter_init_append(reply, &iter);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
- dict_append_entry(&dict, "uuid", DBUS_TYPE_STRING, &prx->uuid128);
-
- dict_append_entry(&dict, "address", DBUS_TYPE_STRING, &prx->address);
-
- if (prx->channel)
- dict_append_entry(&dict, "channel",
- DBUS_TYPE_BYTE, &prx->channel);
-
- boolean = (prx->io ? TRUE : FALSE);
- dict_append_entry(&dict, "enabled", DBUS_TYPE_BOOLEAN, &boolean);
-
- boolean = (prx->rfcomm ? TRUE : FALSE);
- dict_append_entry(&dict, "connected", DBUS_TYPE_BOOLEAN, &boolean);
-
- /* If connected: append the remote address */
- if (boolean) {
- char bda[18];
- const char *pstr = bda;
-
- ba2str(&prx->dst, bda);
- dict_append_entry(&dict, "address", DBUS_TYPE_STRING, &pstr);
- }
-
- dbus_message_iter_close_container(&iter, &dict);
-
- return reply;
-}
-
-static struct {
- const char *str;
- speed_t speed;
-} supported_speed[] = {
- {"50", B50 },
- {"300", B300 },
- {"600", B600 },
- {"1200", B1200 },
- {"1800", B1800 },
- {"2400", B2400 },
- {"4800", B4800 },
- {"9600", B9600 },
- {"19200", B19200 },
- {"38400", B38400 },
- {"57600", B57600 },
- {"115200", B115200 },
- { NULL, B0 }
-};
-
-static speed_t str2speed(const char *str, speed_t *speed)
-{
- int i;
-
- for (i = 0; supported_speed[i].str; i++) {
- if (strcmp(supported_speed[i].str, str) != 0)
- continue;
-
- if (speed)
- *speed = supported_speed[i].speed;
-
- return supported_speed[i].speed;
- }
-
- return B0;
-}
-
-static int set_parity(const char *str, tcflag_t *ctrl)
-{
- if (strcasecmp("even", str) == 0) {
- *ctrl |= PARENB;
- *ctrl &= ~PARODD;
- } else if (strcasecmp("odd", str) == 0) {
- *ctrl |= PARENB;
- *ctrl |= PARODD;
- } else if (strcasecmp("mark", str) == 0)
- *ctrl |= PARENB;
- else if ((strcasecmp("none", str) == 0) ||
- (strcasecmp("space", str) == 0))
- *ctrl &= ~PARENB;
- else
- return -1;
-
- return 0;
-}
-
-static int set_databits(uint8_t databits, tcflag_t *ctrl)
-{
- if (databits < 5 || databits > 8)
- return -EINVAL;
-
- *ctrl &= ~CSIZE;
- switch (databits) {
- case 5:
- *ctrl |= CS5;
- break;
- case 6:
- *ctrl |= CS6;
- break;
- case 7:
- *ctrl |= CS7;
- break;
- case 8:
- *ctrl |= CS8;
- break;
- }
-
- return 0;
-}
-
-static int set_stopbits(uint8_t stopbits, tcflag_t *ctrl)
-{
- /* 1.5 will not be allowed */
- switch (stopbits) {
- case 1:
- *ctrl &= ~CSTOPB;
- return 0;
- case 2:
- *ctrl |= CSTOPB;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static DBusMessage *proxy_set_serial_params(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct serial_proxy *prx = data;
- const char *ratestr, *paritystr;
- uint8_t databits, stopbits;
- tcflag_t ctrl; /* Control mode flags */
- speed_t speed = B0; /* In/Out speed */
-
- /* Don't allow change TTY settings if it is open */
- if (prx->local)
- return btd_error_not_authorized(msg);
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &ratestr,
- DBUS_TYPE_BYTE, &databits,
- DBUS_TYPE_BYTE, &stopbits,
- DBUS_TYPE_STRING, &paritystr,
- DBUS_TYPE_INVALID))
- return NULL;
-
- if (str2speed(ratestr, &speed) == B0)
- return btd_error_invalid_args(msg);
-
- ctrl = prx->proxy_ti.c_cflag;
- if (set_databits(databits, &ctrl) < 0)
- return btd_error_invalid_args(msg);
-
- if (set_stopbits(stopbits, &ctrl) < 0)
- return btd_error_invalid_args(msg);
-
- if (set_parity(paritystr, &ctrl) < 0)
- return btd_error_invalid_args(msg);
-
- prx->proxy_ti.c_cflag = ctrl;
- prx->proxy_ti.c_cflag |= (CLOCAL | CREAD);
- cfsetispeed(&prx->proxy_ti, speed);
- cfsetospeed(&prx->proxy_ti, speed);
-
- return dbus_message_new_method_return(msg);
-}
-
-static const GDBusMethodTable proxy_methods[] = {
- { GDBUS_METHOD("Enable", NULL, NULL, proxy_enable) },
- { GDBUS_METHOD("Disable", NULL, NULL, proxy_disable) },
- { GDBUS_METHOD("GetInfo",
- NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
- proxy_get_info) },
- { GDBUS_METHOD("SetSerialParameters",
- GDBUS_ARGS({ "rate", "s" }, { "data", "y" },
- { "stop", "y" }, { "parity", "s" }),
- NULL, proxy_set_serial_params) },
- { },
-};
-
-static void proxy_path_unregister(gpointer data)
-{
- struct serial_proxy *prx = data;
- int sk;
-
- DBG("Unregistered proxy: %s", prx->address);
-
- if (prx->type != TTY_PROXY)
- goto done;
-
- /* Restore the initial TTY configuration */
- sk = open(prx->address, O_RDWR | O_NOCTTY);
- if (sk >= 0) {
- tcsetattr(sk, TCSAFLUSH, &prx->sys_ti);
- close(sk);
- }
-done:
-
- proxy_free(prx);
-}
-
-static int register_proxy_object(struct serial_proxy *prx)
-{
- struct serial_adapter *adapter = prx->adapter;
- char path[MAX_PATH_LENGTH + 1];
-
- snprintf(path, MAX_PATH_LENGTH, "%s/proxy%d",
- adapter_get_path(adapter->btd_adapter), sk_counter++);
-
- if (!g_dbus_register_interface(adapter->conn, path,
- SERIAL_PROXY_INTERFACE,
- proxy_methods, NULL, NULL,
- prx, proxy_path_unregister)) {
- error("D-Bus failed to register %s path", path);
- return -1;
- }
-
- prx->path = g_strdup(path);
- adapter->proxies = g_slist_append(adapter->proxies, prx);
-
- DBG("Registered proxy: %s", path);
-
- return 0;
-}
-
-static int proxy_tty_register(struct serial_adapter *adapter,
- const char *uuid128, const char *address,
- struct termios *ti,
- struct serial_proxy **proxy)
-{
- struct termios sys_ti;
- struct serial_proxy *prx;
- int sk, ret;
-
- sk = open(address, O_RDONLY | O_NOCTTY);
- if (sk < 0) {
- error("Can't open TTY: %s(%d)", strerror(errno), errno);
- return -EINVAL;
- }
-
- prx = g_new0(struct serial_proxy, 1);
- prx->address = g_strdup(address);
- prx->uuid128 = g_strdup(uuid128);
- prx->type = TTY_PROXY;
- adapter_get_address(adapter->btd_adapter, &prx->src);
- prx->adapter = adapter;
-
- /* Current TTY settings */
- memset(&sys_ti, 0, sizeof(sys_ti));
- tcgetattr(sk, &sys_ti);
- memcpy(&prx->sys_ti, &sys_ti, sizeof(sys_ti));
- close(sk);
-
- if (!ti) {
- /* Use current settings */
- memcpy(&prx->proxy_ti, &sys_ti, sizeof(sys_ti));
- } else {
- /* New TTY settings: user provided */
- memcpy(&prx->proxy_ti, ti, sizeof(*ti));
- }
-
- ret = register_proxy_object(prx);
- if (ret < 0) {
- proxy_free(prx);
- return ret;
- }
-
- *proxy = prx;
-
- return ret;
-}
-
-static int proxy_socket_register(struct serial_adapter *adapter,
- const char *uuid128, const char *address,
- struct serial_proxy **proxy)
-{
- struct serial_proxy *prx;
- int ret;
-
- prx = g_new0(struct serial_proxy, 1);
- prx->address = g_strdup(address);
- prx->uuid128 = g_strdup(uuid128);
- prx->type = UNIX_SOCKET_PROXY;
- adapter_get_address(adapter->btd_adapter, &prx->src);
- prx->adapter = adapter;
-
- ret = register_proxy_object(prx);
- if (ret < 0) {
- proxy_free(prx);
- return ret;
- }
-
- *proxy = prx;
-
- return ret;
-}
-
-static int proxy_tcp_register(struct serial_adapter *adapter,
- const char *uuid128, const char *address,
- struct serial_proxy **proxy)
-{
- struct serial_proxy *prx;
- int ret;
-
- prx = g_new0(struct serial_proxy, 1);
- prx->address = g_strdup(address);
- prx->uuid128 = g_strdup(uuid128);
- prx->type = TCP_SOCKET_PROXY;
- adapter_get_address(adapter->btd_adapter, &prx->src);
- prx->adapter = adapter;
-
- ret = register_proxy_object(prx);
- if (ret < 0) {
- proxy_free(prx);
- return ret;
- }
-
- *proxy = prx;
-
- return ret;
-}
-
-static proxy_type_t addr2type(const char *address)
-{
- struct stat st;
-
- if (stat(address, &st) < 0) {
- /*
- * Unix socket: if the sun_path starts with null byte
- * it refers to abstract namespace. 'x00' will be used
- * to represent the null byte.
- */
- if (strncmp("localhost:", address, 10) == 0)
- return TCP_SOCKET_PROXY;
- if (strncmp("x00", address, 3) != 0)
- return UNKNOWN_PROXY_TYPE;
- else
- return UNIX_SOCKET_PROXY;
- } else {
- /* Filesystem: char device or unix socket */
- if (S_ISCHR(st.st_mode) && strncmp("/dev/", address, 4) == 0)
- return TTY_PROXY;
- else if (S_ISSOCK(st.st_mode))
- return UNIX_SOCKET_PROXY;
- else
- return UNKNOWN_PROXY_TYPE;
- }
-}
-
-static int proxy_addrcmp(gconstpointer proxy, gconstpointer addr)
-{
- const struct serial_proxy *prx = proxy;
- const char *address = addr;
-
- return strcmp(prx->address, address);
-}
-
-static int proxy_pathcmp(gconstpointer proxy, gconstpointer p)
-{
- const struct serial_proxy *prx = proxy;
- const char *path = p;
-
- return strcmp(prx->path, path);
-}
-
-static int register_proxy(struct serial_adapter *adapter,
- const char *uuid_str, const char *address,
- struct serial_proxy **proxy)
-{
- proxy_type_t type;
- int err;
-
- type = addr2type(address);
- if (type == UNKNOWN_PROXY_TYPE)
- return -EINVAL;
-
- /* Only one proxy per address(TTY or unix socket) is allowed */
- if (g_slist_find_custom(adapter->proxies, address, proxy_addrcmp))
- return -EALREADY;
-
- switch (type) {
- case UNIX_SOCKET_PROXY:
- err = proxy_socket_register(adapter, uuid_str, address, proxy);
- break;
- case TTY_PROXY:
- err = proxy_tty_register(adapter, uuid_str, address, NULL,
- proxy);
- break;
- case TCP_SOCKET_PROXY:
- err = proxy_tcp_register(adapter, uuid_str, address, proxy);
- break;
- default:
- err = -EINVAL;
- }
-
- if (err < 0)
- return err;
-
- g_dbus_emit_signal(adapter->conn,
- adapter_get_path(adapter->btd_adapter),
- SERIAL_MANAGER_INTERFACE, "ProxyCreated",
- DBUS_TYPE_STRING, &(*proxy)->path,
- DBUS_TYPE_INVALID);
-
- return 0;
-}
-
-static void unregister_proxy(struct serial_proxy *proxy)
-{
- struct serial_adapter *adapter = proxy->adapter;
- char *path = g_strdup(proxy->path);
-
- if (proxy->watch > 0)
- g_dbus_remove_watch(adapter->conn, proxy->watch);
-
- g_dbus_emit_signal(adapter->conn,
- adapter_get_path(adapter->btd_adapter),
- SERIAL_MANAGER_INTERFACE, "ProxyRemoved",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
-
- adapter->proxies = g_slist_remove(adapter->proxies, proxy);
-
- g_dbus_unregister_interface(adapter->conn, path,
- SERIAL_PROXY_INTERFACE);
-
- g_free(path);
-}
-
-static void watch_proxy(DBusConnection *connection, void *user_data)
-{
- struct serial_proxy *proxy = user_data;
-
- proxy->watch = 0;
- unregister_proxy(proxy);
-}
-
-static DBusMessage *create_proxy(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct serial_adapter *adapter = data;
- struct serial_proxy *proxy;
- const char *pattern, *address;
- char *uuid_str;
- int err;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &pattern,
- DBUS_TYPE_STRING, &address,
- DBUS_TYPE_INVALID))
- return NULL;
-
- uuid_str = bt_name2string(pattern);
- if (!uuid_str)
- return btd_error_invalid_args(msg);
-
- err = register_proxy(adapter, uuid_str, address, &proxy);
- g_free(uuid_str);
-
- if (err == -EINVAL)
- return btd_error_invalid_args(msg);
- else if (err == -EALREADY)
- return btd_error_already_exists(msg);
- else if (err < 0)
- return btd_error_failed(msg, strerror(-err));
-
- proxy->owner = g_strdup(dbus_message_get_sender(msg));
- proxy->watch = g_dbus_add_disconnect_watch(conn, proxy->owner,
- watch_proxy,
- proxy, NULL);
-
- return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &proxy->path,
- DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *list_proxies(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct serial_adapter *adapter = data;
- const GSList *l;
- DBusMessage *reply;
- DBusMessageIter iter, iter_array;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- dbus_message_iter_init_append(reply, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING_AS_STRING, &iter_array);
-
- for (l = adapter->proxies; l; l = l->next) {
- struct serial_proxy *prx = l->data;
-
- dbus_message_iter_append_basic(&iter_array,
- DBUS_TYPE_STRING, &prx->path);
- }
-
- dbus_message_iter_close_container(&iter, &iter_array);
-
- return reply;
-}
-
-static DBusMessage *remove_proxy(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct serial_adapter *adapter = data;
- struct serial_proxy *prx;
- const char *path, *sender;
- GSList *l;
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID))
- return NULL;
-
- l = g_slist_find_custom(adapter->proxies, path, proxy_pathcmp);
- if (!l)
- return btd_error_does_not_exist(msg);
-
- prx = l->data;
-
- sender = dbus_message_get_sender(msg);
- if (g_strcmp0(prx->owner, sender) != 0)
- return btd_error_not_authorized(msg);
-
- unregister_proxy(prx);
-
- return dbus_message_new_method_return(msg);
-}
-
-static void manager_path_unregister(void *data)
-{
- struct serial_adapter *adapter = data;
- GSList *l;
-
- /* Remove proxy objects */
- for (l = adapter->proxies; l; l = l->next) {
- struct serial_proxy *prx = l->data;
- char *path = g_strdup(prx->path);
-
- g_dbus_unregister_interface(adapter->conn, path,
- SERIAL_PROXY_INTERFACE);
- g_free(path);
- }
-
- if (adapter->conn)
- dbus_connection_unref(adapter->conn);
-
- adapters = g_slist_remove(adapters, adapter);
- g_slist_free(adapter->proxies);
- btd_adapter_unref(adapter->btd_adapter);
- g_free(adapter);
-}
-
-static const GDBusMethodTable manager_methods[] = {
- { GDBUS_METHOD("CreateProxy",
- GDBUS_ARGS({ "pattern", "s" },
- { "address", "s" }),
- GDBUS_ARGS({ "path", "s" }),
- create_proxy) },
- { GDBUS_METHOD("ListProxies",
- NULL, GDBUS_ARGS({ "paths", "as" }),
- list_proxies) },
- { GDBUS_METHOD("RemoveProxy",
- GDBUS_ARGS({ "path", "s" }), NULL,
- remove_proxy) },
- { },
-};
-
-static const GDBusSignalTable manager_signals[] = {
- { GDBUS_SIGNAL("ProxyCreated", GDBUS_ARGS({ "path", "s" })) },
- { GDBUS_SIGNAL("ProxyRemoved", GDBUS_ARGS({ "path", "s" })) },
- { }
-};
-
-static struct serial_adapter *find_adapter(GSList *list,
- struct btd_adapter *btd_adapter)
-{
- for (; list; list = list->next) {
- struct serial_adapter *adapter = list->data;
-
- if (adapter->btd_adapter == btd_adapter)
- return adapter;
- }
-
- return NULL;
-}
-
-static void serial_proxy_init(struct serial_adapter *adapter)
-{
- GKeyFile *config;
- GError *gerr = NULL;
- const char *file = CONFIGDIR "/serial.conf";
- char **group_list;
- int i;
-
- config = g_key_file_new();
-
- if (!g_key_file_load_from_file(config, file, 0, &gerr)) {
- error("Parsing %s failed: %s", file, gerr->message);
- g_error_free(gerr);
- g_key_file_free(config);
- return;
- }
-
- group_list = g_key_file_get_groups(config, NULL);
-
- for (i = 0; group_list[i] != NULL; i++) {
- char *group_str = group_list[i], *uuid_str, *address;
- int err;
- struct serial_proxy *prx;
-
- /* string length of "Proxy" is 5 */
- if (strlen(group_str) < 5 || strncmp(group_str, "Proxy", 5))
- continue;
-
- uuid_str = g_key_file_get_string(config, group_str, "UUID",
- &gerr);
- if (gerr) {
- DBG("%s: %s", file, gerr->message);
- g_error_free(gerr);
- g_key_file_free(config);
- g_strfreev(group_list);
- return;
- }
-
- address = g_key_file_get_string(config, group_str, "Address",
- &gerr);
- if (gerr) {
- DBG("%s: %s", file, gerr->message);
- g_error_free(gerr);
- g_key_file_free(config);
- g_free(uuid_str);
- g_strfreev(group_list);
- return;
- }
-
- err = register_proxy(adapter, uuid_str, address, &prx);
- if (err == -EINVAL)
- error("Invalid address.");
- else if (err == -EALREADY)
- DBG("Proxy already exists.");
- else if (err < 0)
- error("Proxy creation failed (%s)", strerror(-err));
- else {
- err = enable_proxy(prx);
- if (err < 0)
- error("Proxy enable failed (%s)",
- strerror(-err));
- }
-
- g_free(uuid_str);
- g_free(address);
- }
-
- g_strfreev(group_list);
- g_key_file_free(config);
-}
-
-int proxy_register(DBusConnection *conn, struct btd_adapter *btd_adapter)
-{
- struct serial_adapter *adapter;
- const char *path;
-
- adapter = find_adapter(adapters, btd_adapter);
- if (adapter)
- return -EINVAL;
-
- adapter = g_new0(struct serial_adapter, 1);
- adapter->conn = dbus_connection_ref(conn);
- adapter->btd_adapter = btd_adapter_ref(btd_adapter);
-
- path = adapter_get_path(btd_adapter);
-
- if (!g_dbus_register_interface(conn, path,
- SERIAL_MANAGER_INTERFACE,
- manager_methods, manager_signals, NULL,
- adapter, manager_path_unregister)) {
- error("Failed to register %s interface to %s",
- SERIAL_MANAGER_INTERFACE, path);
- return -1;
- }
-
- adapters = g_slist_append(adapters, adapter);
-
- DBG("Registered interface %s on path %s",
- SERIAL_MANAGER_INTERFACE, path);
-
- serial_proxy_init(adapter);
-
- return 0;
-}
-
-void proxy_unregister(struct btd_adapter *btd_adapter)
-{
- struct serial_adapter *adapter;
-
- adapter = find_adapter(adapters, btd_adapter);
- if (!adapter)
- return;
-
- g_dbus_unregister_interface(adapter->conn,
- adapter_get_path(btd_adapter),
- SERIAL_MANAGER_INTERFACE);
-}
diff --git a/serial/proxy.h b/serial/proxy.h
deleted file mode 100644
index 7871665..0000000
--- a/serial/proxy.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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
- *
- */
-
-int proxy_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
-void proxy_unregister(struct btd_adapter *btd_adapter);
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 12/21] serial: remove unneeded headers include
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (9 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 11/21] serial: remove SerialProxy interface Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 13/21] input: remove unneeded header inclusions Gustavo Padovan
` (8 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
serial/manager.c | 21 ---------------------
serial/port.c | 8 --------
2 files changed, 29 deletions(-)
diff --git a/serial/manager.c b/serial/manager.c
index a84ce03..6f3fc1f 100644
--- a/serial/manager.c
+++ b/serial/manager.c
@@ -25,43 +25,22 @@
#include <config.h>
#endif
-#include <ctype.h>
-#include <dirent.h>
#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
-#include <bluetooth/rfcomm.h>
#include <bluetooth/uuid.h>
-#include <glib.h>
#include <gdbus.h>
-#include "../src/dbus-common.h"
#include "adapter.h"
#include "device.h"
#include "log.h"
-#include "error.h"
#include "port.h"
-#include "storage.h"
#include "manager.h"
-#include "sdpd.h"
-#include "glib-helper.h"
static DBusConnection *connection = NULL;
diff --git a/serial/port.c b/serial/port.c
index f90bb6a..2422cfe 100644
--- a/serial/port.c
+++ b/serial/port.c
@@ -26,15 +26,9 @@
#endif
#include <errno.h>
-#include <stdio.h>
-#include <stdint.h>
#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <bluetooth/bluetooth.h>
@@ -45,8 +39,6 @@
#include <glib.h>
#include <gdbus.h>
-#include "../src/dbus-common.h"
-
#include "log.h"
#include "glib-helper.h"
#include "sdp-client.h"
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 13/21] input: remove unneeded header inclusions
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (10 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 12/21] serial: remove unneeded headers include Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 14/21] serial: remove old way to connect to a serial port Gustavo Padovan
` (7 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
input/device.c | 5 -----
input/fakehid.c | 4 ----
input/manager.c | 3 ---
3 files changed, 12 deletions(-)
diff --git a/input/device.c b/input/device.c
index 8ed722b..decf6d0 100644
--- a/input/device.c
+++ b/input/device.c
@@ -29,9 +29,6 @@
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hidp.h>
@@ -39,8 +36,6 @@
#include <bluetooth/sdp_lib.h>
#include <bluetooth/uuid.h>
-#include <glib.h>
-#include <dbus/dbus.h>
#include <gdbus.h>
#include "log.h"
diff --git a/input/fakehid.c b/input/fakehid.c
index 3181538..3be1489 100644
--- a/input/fakehid.c
+++ b/input/fakehid.c
@@ -25,12 +25,8 @@
#include <config.h>
#endif
-#include <stdio.h>
-#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
#include <bluetooth/bluetooth.h>
diff --git a/input/manager.c b/input/manager.c
index 5cc552b..3572ea9 100644
--- a/input/manager.c
+++ b/input/manager.c
@@ -28,13 +28,10 @@
#include <errno.h>
#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <bluetooth/uuid.h>
-#include <gdbus.h>
-
#include "log.h"
#include "../src/adapter.h"
#include "../src/device.h"
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 14/21] serial: remove old way to connect to a serial port
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (11 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 13/21] input: remove unneeded header inclusions Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 15/21] emulator: move it to the tools folder Gustavo Padovan
` (6 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Only the fd-passing connect is available now.
---
doc/serial-api.txt | 32 +--------
serial/port.c | 202 +++-------------------------------------------------
2 files changed, 9 insertions(+), 225 deletions(-)
diff --git a/doc/serial-api.txt b/doc/serial-api.txt
index 42afe3d..9bb0054 100644
--- a/doc/serial-api.txt
+++ b/doc/serial-api.txt
@@ -11,22 +11,7 @@ Service org.bluez
Interface org.bluez.Serial
Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-Methods string Connect(string pattern)
-
- Connects to a specific RFCOMM based service on a
- remote device and then creates a RFCOMM TTY
- device for it. The RFCOMM TTY device is returned.
-
- Possible patterns: UUID 128 bit as string
- Profile short names, e.g: spp, dun
- RFCOMM channel as string, 1-30
-
- Possible errors: org.bluez.Error.InvalidArguments
- org.bluez.Error.InProgress
- org.bluez.Error.ConnectionAttemptFailed
- org.bluez.Error.NotSupported
-
-Methods fd ConnectFD(string pattern) [experimental]
+Methods fd Connect(string pattern)
Connects to a specific RFCOMM based service on a
remote device and returns a file descriptor to talk
@@ -40,18 +25,3 @@ Methods fd ConnectFD(string pattern) [experimental]
org.bluez.Error.InProgress
org.bluez.Error.ConnectionAttemptFailed
org.bluez.Error.NotSupported
-
-
- void Disconnect(string device)
-
- Disconnect a RFCOMM TTY device that has been
- created by Connect method.
-
- To abort a connection attempt in case of errors or
- timeouts in the client it is fine to call this method.
-
- In that case one of patterns of the Connect method should
- be supplied instead of the TTY device.
-
- Possible errors: org.bluez.Error.InvalidArguments
- org.bluez.Error.DoesNotExist
diff --git a/serial/port.c b/serial/port.c
index 2422cfe..f2b7184 100644
--- a/serial/port.c
+++ b/serial/port.c
@@ -69,8 +69,6 @@ struct serial_port {
int16_t id; /* RFCOMM device id */
uint8_t channel; /* RFCOMM channel */
char *uuid; /* service identification */
- char *dev; /* RFCOMM device name */
- int fd; /* Opened file descriptor */
GIOChannel *io; /* BtIO channel */
guint listener_id;
struct serial_device *device;
@@ -111,9 +109,6 @@ static struct serial_port *find_port(GSList *ports, const char *pattern)
if (endptr && *endptr == '\0' && port->channel == channel)
return port;
- if (port->dev && !strcmp(port->dev, pattern))
- return port;
-
if (!port->uuid)
continue;
@@ -130,12 +125,8 @@ static struct serial_port *find_port(GSList *ports, const char *pattern)
return NULL;
}
-static int port_release(struct serial_port *port)
+static void port_release(struct serial_port *port)
{
- struct rfcomm_dev_req req;
- int rfcomm_ctl;
- int err = 0;
-
if (port->id < 0) {
if (port->io) {
g_io_channel_shutdown(port->io, TRUE, NULL);
@@ -145,41 +136,7 @@ static int port_release(struct serial_port *port)
bt_cancel_discovery(&port->device->src,
&port->device->dst);
- return 0;
}
-
- DBG("Serial port %s released", port->dev);
-
- rfcomm_ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
- if (rfcomm_ctl < 0)
- return -errno;
-
- if (port->fd >= 0) {
- close(port->fd);
- port->fd = -1;
- }
-
- memset(&req, 0, sizeof(req));
- req.dev_id = port->id;
-
- /*
- * We are hitting a kernel bug inside RFCOMM code when
- * RFCOMM_HANGUP_NOW bit is set on request's flags passed to
- * ioctl(RFCOMMRELEASEDEV)!
- */
- req.flags = (1 << RFCOMM_HANGUP_NOW);
-
- if (ioctl(rfcomm_ctl, RFCOMMRELEASEDEV, &req) < 0) {
- err = -errno;
- error("Can't release device %s: %s (%d)",
- port->dev, strerror(-err), -err);
- }
-
- g_free(port->dev);
- port->dev = NULL;
- port->id = -1;
- close(rfcomm_ctl);
- return err;
}
static void serial_port_free(void *data)
@@ -231,74 +188,12 @@ void port_release_all(void)
g_slist_free_full(devices, serial_device_free);
}
-static void open_notify(int fd, int err, struct serial_port *port)
-{
- struct serial_device *device = port->device;
- DBusMessage *reply;
-
- if (err < 0) {
- /* Max tries exceeded */
- port_release(port);
- reply = btd_error_failed(port->msg, strerror(-err));
- } else {
- port->fd = fd;
- reply = g_dbus_create_reply(port->msg,
- DBUS_TYPE_STRING, &port->dev,
- DBUS_TYPE_INVALID);
- }
-
- /* Reply to the requestor */
- g_dbus_send_message(device->conn, reply);
-}
-
-static gboolean open_continue(gpointer user_data)
-{
- struct serial_port *port = user_data;
- int fd;
- static int ntries = MAX_OPEN_TRIES;
-
- if (!port->listener_id)
- return FALSE; /* Owner exited */
-
- fd = open(port->dev, O_RDONLY | O_NOCTTY);
- if (fd < 0) {
- int err = -errno;
- error("Could not open %s: %s (%d)",
- port->dev, strerror(-err), -err);
- if (!--ntries) {
- /* Reporting error */
- open_notify(fd, err, port);
- ntries = MAX_OPEN_TRIES;
- return FALSE;
- }
- return TRUE;
- }
-
- /* Connection succeeded */
- open_notify(fd, 0, port);
- return FALSE;
-}
-
-static int port_open(struct serial_port *port)
-{
- int fd;
-
- fd = open(port->dev, O_RDONLY | O_NOCTTY);
- if (fd < 0) {
- g_timeout_add(OPEN_WAIT, open_continue, port);
- return -EINPROGRESS;
- }
-
- return fd;
-}
-
static void rfcomm_connect_cb(GIOChannel *chan, GError *conn_err,
gpointer user_data)
{
struct serial_port *port = user_data;
struct serial_device *device = port->device;
- struct rfcomm_dev_req req;
- int sk, fd;
+ int sk;
DBusMessage *reply;
/* Owner exited? */
@@ -308,60 +203,18 @@ static void rfcomm_connect_cb(GIOChannel *chan, GError *conn_err,
if (conn_err) {
error("%s", conn_err->message);
reply = btd_error_failed(port->msg, conn_err->message);
- goto fail;
- }
-
- sk = g_io_channel_unix_get_fd(chan);
-
- if (dbus_message_has_member(port->msg, "ConnectFD")) {
- reply = g_dbus_create_reply(port->msg, DBUS_TYPE_UNIX_FD, &sk,
- DBUS_TYPE_INVALID);
g_dbus_send_message(device->conn, reply);
-
- close(sk);
-
- g_dbus_remove_watch(device->conn, port->listener_id);
- port->listener_id = 0;
-
- return;
- }
-
- memset(&req, 0, sizeof(req));
- req.dev_id = -1;
- req.flags = (1 << RFCOMM_REUSE_DLC);
- bacpy(&req.src, &device->src);
- bacpy(&req.dst, &device->dst);
- req.channel = port->channel;
-
- g_io_channel_unref(port->io);
- port->io = NULL;
-
- port->id = ioctl(sk, RFCOMMCREATEDEV, &req);
- if (port->id < 0) {
- int err = -errno;
- error("ioctl(RFCOMMCREATEDEV): %s (%d)", strerror(-err), -err);
- reply = btd_error_failed(port->msg, strerror(-err));
- g_io_channel_shutdown(chan, TRUE, NULL);
goto fail;
}
- port->dev = g_strdup_printf("/dev/rfcomm%d", port->id);
-
- DBG("Serial port %s created", port->dev);
-
- g_io_channel_shutdown(chan, TRUE, NULL);
-
- /* Addressing connect port */
- fd = port_open(port);
- if (fd < 0)
- /* Open in progress: Wait the callback */
- return;
+ sk = g_io_channel_unix_get_fd(chan);
+ reply = g_dbus_create_reply(port->msg, DBUS_TYPE_UNIX_FD, &sk,
+ DBUS_TYPE_INVALID);
+ g_dbus_send_message(device->conn, reply);
- open_notify(fd, 0, port);
- return;
+ close(sk);
fail:
- g_dbus_send_message(device->conn, reply);
g_dbus_remove_watch(device->conn, port->listener_id);
port->listener_id = 0;
}
@@ -468,7 +321,6 @@ static struct serial_port *create_port(struct serial_device *device,
port->channel = channel;
port->device = device;
port->id = -1;
- port->fd = -1;
device->ports = g_slist_append(device->ports, port);
@@ -521,47 +373,10 @@ static DBusMessage *port_connect(DBusConnection *conn,
return NULL;
}
-static DBusMessage *port_disconnect(DBusConnection *conn,
- DBusMessage *msg, void *user_data)
-{
- struct serial_device *device = user_data;
- struct serial_port *port;
- const char *dev, *owner, *caller;
-
- if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &dev,
- DBUS_TYPE_INVALID) == FALSE)
- return NULL;
-
- port = find_port(device->ports, dev);
- if (!port)
- return btd_error_does_not_exist(msg);
-
- if (!port->listener_id)
- return btd_error_not_connected(msg);
-
- owner = dbus_message_get_sender(port->msg);
- caller = dbus_message_get_sender(msg);
- if (!g_str_equal(owner, caller))
- return btd_error_not_authorized(msg);
-
- port_release(port);
-
- g_dbus_remove_watch(conn, port->listener_id);
- port->listener_id = 0;
-
- return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
static const GDBusMethodTable port_methods[] = {
{ GDBUS_ASYNC_METHOD("Connect",
- GDBUS_ARGS({ "pattern", "s" }), GDBUS_ARGS({ "tty", "s" }),
- port_connect) },
- { GDBUS_ASYNC_METHOD("ConnectFD",
- GDBUS_ARGS({ "pattern", "s" }), GDBUS_ARGS({ "fd", "s" }),
+ GDBUS_ARGS({ "pattern", "s" }), GDBUS_ARGS({ "fd", "s" }),
port_connect) },
- { GDBUS_METHOD("Disconnect",
- GDBUS_ARGS({ "device", "s" }), NULL,
- port_disconnect) },
{ }
};
@@ -615,7 +430,6 @@ int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
port->channel = channel;
port->device = device;
port->id = -1;
- port->fd = -1;
device->ports = g_slist_append(device->ports, port);
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 15/21] emulator: move it to the tools folder
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (12 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 14/21] serial: remove old way to connect to a serial port Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 16/21] btmgmt: move to " Gustavo Padovan
` (5 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
.gitignore | 2 +-
Makefile.tools | 12 +-
emulator/btdev.c | 1076 -----------------------------------------------
emulator/btdev.h | 38 --
emulator/main.c | 73 ----
emulator/server.c | 288 -------------
emulator/server.h | 30 --
emulator/vhci.c | 133 ------
emulator/vhci.h | 35 --
tools/emulator/btdev.c | 1076 +++++++++++++++++++++++++++++++++++++++++++++++
tools/emulator/btdev.h | 38 ++
tools/emulator/main.c | 73 ++++
tools/emulator/server.c | 288 +++++++++++++
tools/emulator/server.h | 30 ++
tools/emulator/vhci.c | 133 ++++++
tools/emulator/vhci.h | 35 ++
16 files changed, 1680 insertions(+), 1680 deletions(-)
delete mode 100644 emulator/btdev.c
delete mode 100644 emulator/btdev.h
delete mode 100644 emulator/main.c
delete mode 100644 emulator/server.c
delete mode 100644 emulator/server.h
delete mode 100644 emulator/vhci.c
delete mode 100644 emulator/vhci.h
create mode 100644 tools/emulator/btdev.c
create mode 100644 tools/emulator/btdev.h
create mode 100644 tools/emulator/main.c
create mode 100644 tools/emulator/server.c
create mode 100644 tools/emulator/server.h
create mode 100644 tools/emulator/vhci.c
create mode 100644 tools/emulator/vhci.h
diff --git a/.gitignore b/.gitignore
index 137d2e5..7bbefc9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,7 +86,7 @@ compat/pand
unit/test-eir
mgmt/btmgmt
monitor/btmon
-emulator/btvirt
+tools/emulator/btvirt
doc/*.bak
doc/*.stamp
diff --git a/Makefile.tools b/Makefile.tools
index 533ad9b..f7c6f9f 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -50,7 +50,7 @@ tools_ppporc_LDADD = lib/libbluetooth-private.la
tools_hcieventmask_LDADD = lib/libbluetooth-private.la
-noinst_PROGRAMS += mgmt/btmgmt monitor/btmon emulator/btvirt
+noinst_PROGRAMS += mgmt/btmgmt monitor/btmon tools/emulator/btvirt
mgmt_btmgmt_SOURCES = mgmt/main.c src/glib-helper.c
mgmt_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
@@ -63,11 +63,11 @@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
monitor/packet.h monitor/packet.c
monitor_btmon_LDADD = lib/libbluetooth-private.la
-emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
- monitor/mainloop.h monitor/mainloop.c \
- emulator/server.h emulator/server.c \
- emulator/vhci.h emulator/vhci.c \
- emulator/btdev.h emulator/btdev.c
+emulator_btvirt_SOURCES = tools/emulator/main.c monitor/bt.h \
+ monitor/mainloop.h monitor/mainloop.c \
+ tools/emulator/server.h tools/emulator/server.c \
+ tools/emulator/vhci.h tools/emulator/vhci.c \
+ tools/emulator/btdev.h tools/emulator/btdev.c
if READLINE
bin_PROGRAMS += attrib/gatttool
diff --git a/emulator/btdev.c b/emulator/btdev.c
deleted file mode 100644
index 7d4517a..0000000
--- a/emulator/btdev.c
+++ /dev/null
@@ -1,1076 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2012 Intel Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "bt.h"
-#include "btdev.h"
-
-#define le16_to_cpu(val) (val)
-#define cpu_to_le16(val) (val)
-
-struct btdev {
- struct btdev *conn;
-
- btdev_send_func send_handler;
- void *send_data;
-
- uint16_t manufacturer;
- uint8_t version;
- uint16_t revision;
- uint8_t commands[64];
- uint8_t features[8];
- uint16_t acl_mtu;
- uint16_t acl_max_pkt;
- uint8_t country_code;
- uint8_t bdaddr[6];
- uint8_t le_features[8];
- uint8_t le_states[8];
-
- uint16_t default_link_policy;
- uint8_t event_mask[8];
- uint8_t event_filter;
- uint8_t name[248];
- uint8_t dev_class[3];
- uint16_t voice_setting;
- uint16_t conn_accept_timeout;
- uint16_t page_timeout;
- uint8_t scan_enable;
- uint8_t auth_enable;
- uint8_t inquiry_mode;
- uint8_t afh_assess_mode;
- uint8_t ext_inquiry_fec;
- uint8_t ext_inquiry_rsp[240];
- uint8_t simple_pairing_mode;
- uint8_t le_supported;
- uint8_t le_simultaneous;
- uint8_t le_event_mask[8];
-};
-
-#define MAX_BTDEV_ENTRIES 16
-
-static struct btdev *btdev_list[MAX_BTDEV_ENTRIES] = { };
-
-static inline int add_btdev(struct btdev *btdev)
-{
- int i, index = -1;
-
- for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
- if (btdev_list[i] == NULL) {
- index = i;
- btdev_list[index] = btdev;
- break;
- }
- }
-
- return index;
-}
-
-static inline int del_btdev(struct btdev *btdev)
-{
- int i, index = -1;
-
- for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
- if (btdev_list[i] == btdev) {
- index = i;
- btdev_list[index] = NULL;
- break;
- }
- }
-
- return index;
-}
-
-static inline struct btdev *find_btdev_by_bdaddr(const uint8_t *bdaddr)
-{
- int i;
-
- for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
- if (btdev_list[i] && !memcmp(btdev_list[i]->bdaddr, bdaddr, 6))
- return btdev_list[i];
- }
-
- return NULL;
-}
-
-static void hexdump(const unsigned char *buf, uint16_t len)
-{
- static const char hexdigits[] = "0123456789abcdef";
- char str[68];
- uint16_t i;
-
- if (!len)
- return;
-
- for (i = 0; i < len; i++) {
- str[((i % 16) * 3) + 0] = hexdigits[buf[i] >> 4];
- str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf];
- str[((i % 16) * 3) + 2] = ' ';
- str[(i % 16) + 49] = isprint(buf[i]) ? buf[i] : '.';
-
- if ((i + 1) % 16 == 0) {
- str[47] = ' ';
- str[48] = ' ';
- str[65] = '\0';
- printf("%-12c%s\n", ' ', str);
- str[0] = ' ';
- }
- }
-
- if (i % 16 > 0) {
- uint16_t j;
- for (j = (i % 16); j < 16; j++) {
- str[(j * 3) + 0] = ' ';
- str[(j * 3) + 1] = ' ';
- str[(j * 3) + 2] = ' ';
- str[j + 49] = ' ';
- }
- str[47] = ' ';
- str[48] = ' ';
- str[65] = '\0';
- printf("%-12c%s\n", ' ', str);
- }
-}
-
-static void get_bdaddr(uint16_t id, uint8_t *bdaddr)
-{
- bdaddr[0] = id & 0xff;
- bdaddr[1] = id >> 8;
- bdaddr[2] = 0x00;
- bdaddr[3] = 0x01;
- bdaddr[4] = 0xaa;
- bdaddr[5] = 0x00;
-}
-
-struct btdev *btdev_create(uint16_t id)
-{
- struct btdev *btdev;
-
- btdev = malloc(sizeof(*btdev));
- if (!btdev)
- return NULL;
-
- memset(btdev, 0, sizeof(*btdev));
-
- btdev->manufacturer = 63;
- btdev->version = 0x06;
- btdev->revision = 0x0000;
-
- btdev->features[0] |= 0x04; /* Encryption */
- btdev->features[0] |= 0x20; /* Role switch */
- btdev->features[0] |= 0x80; /* Sniff mode */
- btdev->features[1] |= 0x08; /* SCO link */
- btdev->features[3] |= 0x40; /* RSSI with inquiry results */
- btdev->features[3] |= 0x80; /* Extended SCO link */
- btdev->features[4] |= 0x08; /* AFH capable slave */
- btdev->features[4] |= 0x10; /* AFH classification slave */
- btdev->features[4] |= 0x40; /* LE Supported */
- btdev->features[5] |= 0x02; /* Sniff subrating */
- btdev->features[5] |= 0x04; /* Pause encryption */
- btdev->features[5] |= 0x08; /* AFH capable master */
- btdev->features[5] |= 0x10; /* AFH classification master */
- btdev->features[6] |= 0x01; /* Extended Inquiry Response */
- btdev->features[6] |= 0x02; /* Simultaneous LE and BR/EDR */
- btdev->features[6] |= 0x08; /* Secure Simple Pairing */
- btdev->features[6] |= 0x10; /* Encapsulated PDU */
- btdev->features[6] |= 0x20; /* Erroneous Data Reporting */
- btdev->features[6] |= 0x40; /* Non-flushable Packet Boundary Flag */
- btdev->features[7] |= 0x01; /* Link Supervision Timeout Event */
- btdev->features[7] |= 0x02; /* Inquiry TX Power Level */
- btdev->features[7] |= 0x80; /* Extended features */
-
- btdev->acl_mtu = 192;
- btdev->acl_max_pkt = 1;
-
- btdev->country_code = 0x00;
-
- get_bdaddr(id, btdev->bdaddr);
-
- add_btdev(btdev);
-
- return btdev;
-}
-
-void btdev_destroy(struct btdev *btdev)
-{
- if (!btdev)
- return;
-
- del_btdev(btdev);
-
- free(btdev);
-}
-
-void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
- void *user_data)
-{
- if (!btdev)
- return;
-
- btdev->send_handler = handler;
- btdev->send_data = user_data;
-}
-
-static void send_packet(struct btdev *btdev, const void *data, uint16_t len)
-{
- if (!btdev->send_handler)
- return;
-
- btdev->send_handler(data, len, btdev->send_data);
-}
-
-static void send_event(struct btdev *btdev, uint8_t event,
- const void *data, uint8_t len)
-{
- struct bt_hci_evt_hdr *hdr;
- uint16_t pkt_len;
- void *pkt_data;
-
- pkt_len = 1 + sizeof(*hdr) + len;
-
- pkt_data = malloc(pkt_len);
- if (!pkt_data)
- return;
-
- ((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
-
- hdr = pkt_data + 1;
- hdr->evt = event;
- hdr->plen = len;
-
- if (len > 0)
- memcpy(pkt_data + 1 + sizeof(*hdr), data, len);
-
- send_packet(btdev, pkt_data, pkt_len);
-
- free(pkt_data);
-}
-
-static void cmd_complete(struct btdev *btdev, uint16_t opcode,
- const void *data, uint8_t len)
-{
- struct bt_hci_evt_hdr *hdr;
- struct bt_hci_evt_cmd_complete *cc;
- uint16_t pkt_len;
- void *pkt_data;
-
- pkt_len = 1 + sizeof(*hdr) + sizeof(*cc) + len;
-
- pkt_data = malloc(pkt_len);
- if (!pkt_data)
- return;
-
- ((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
-
- hdr = pkt_data + 1;
- hdr->evt = BT_HCI_EVT_CMD_COMPLETE;
- hdr->plen = sizeof(*cc) + len;
-
- cc = pkt_data + 1 + sizeof(*hdr);
- cc->ncmd = 0x01;
- cc->opcode = cpu_to_le16(opcode);
-
- if (len > 0)
- memcpy(pkt_data + 1 + sizeof(*hdr) + sizeof(*cc), data, len);
-
- send_packet(btdev, pkt_data, pkt_len);
-
- free(pkt_data);
-}
-
-static void cmd_status(struct btdev *btdev, uint8_t status, uint16_t opcode)
-{
- struct bt_hci_evt_cmd_status cs;
-
- cs.status = status;
- cs.ncmd = 0x01;
- cs.opcode = cpu_to_le16(opcode);
-
- send_event(btdev, BT_HCI_EVT_CMD_STATUS, &cs, sizeof(cs));
-}
-
-static void num_completed_packets(struct btdev *btdev)
-{
- if (btdev->conn) {
- struct bt_hci_evt_num_completed_packets ncp;
-
- ncp.num_handles = 1;
- ncp.handle = cpu_to_le16(42);
- ncp.count = cpu_to_le16(1);
-
- send_event(btdev, BT_HCI_EVT_NUM_COMPLETED_PACKETS,
- &ncp, sizeof(ncp));
- }
-}
-
-static void inquiry_complete(struct btdev *btdev, uint8_t status)
-{
- struct bt_hci_evt_inquiry_complete ic;
- int i;
-
- for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
- if (!btdev_list[i] || btdev_list[i] == btdev)
- continue;
-
- if (!(btdev_list[i]->scan_enable & 0x02))
- continue;
-
- if (btdev->inquiry_mode == 0x02 &&
- btdev_list[i]->ext_inquiry_rsp[0]) {
- struct bt_hci_evt_ext_inquiry_result ir;
-
- ir.num_resp = 0x01;
- memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
- memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
- ir.rssi = -60;
- memcpy(ir.data, btdev_list[i]->ext_inquiry_rsp, 240);
-
- send_event(btdev, BT_HCI_EVT_EXT_INQUIRY_RESULT,
- &ir, sizeof(ir));
- continue;
- }
-
- if (btdev->inquiry_mode > 0x00) {
- struct bt_hci_evt_inquiry_result_with_rssi ir;
-
- ir.num_resp = 0x01;
- memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
- memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
- ir.rssi = -60;
-
- send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI,
- &ir, sizeof(ir));
- } else {
- struct bt_hci_evt_inquiry_result ir;
-
- ir.num_resp = 0x01;
- memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
- memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
-
- send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT,
- &ir, sizeof(ir));
- }
- }
-
- ic.status = status;
-
- send_event(btdev, BT_HCI_EVT_INQUIRY_COMPLETE, &ic, sizeof(ic));
-}
-
-static void conn_complete(struct btdev *btdev,
- const uint8_t *bdaddr, uint8_t status)
-{
- struct bt_hci_evt_conn_complete cc;
-
- if (!status) {
- struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
-
- btdev->conn = remote;
- remote->conn = btdev;
-
- cc.status = status;
- memcpy(cc.bdaddr, btdev->bdaddr, 6);
- cc.encr_mode = 0x00;
-
- cc.handle = cpu_to_le16(42);
- cc.link_type = 0x01;
-
- send_event(remote, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
-
- cc.handle = cpu_to_le16(42);
- cc.link_type = 0x01;
- } else {
- cc.handle = cpu_to_le16(0x0000);
- cc.link_type = 0x01;
- }
-
- cc.status = status;
- memcpy(cc.bdaddr, bdaddr, 6);
- cc.encr_mode = 0x00;
-
- send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
-}
-
-static void conn_request(struct btdev *btdev, const uint8_t *bdaddr)
-{
- struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
-
- if (remote) {
- if (remote->scan_enable & 0x01) {
- struct bt_hci_evt_conn_request cr;
-
- memcpy(cr.bdaddr, btdev->bdaddr, 6);
- memcpy(cr.dev_class, btdev->dev_class, 3);
- cr.link_type = 0x01;
-
- send_event(remote, BT_HCI_EVT_CONN_REQUEST,
- &cr, sizeof(cr));
- } else
- conn_complete(btdev, bdaddr, BT_HCI_ERR_PAGE_TIMEOUT);
- } else
- conn_complete(btdev, bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
-}
-
-static void disconnect_complete(struct btdev *btdev, uint16_t handle,
- uint8_t reason)
-{
- struct bt_hci_evt_disconnect_complete dc;
- struct btdev *remote;
-
- if (!btdev) {
- dc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
- dc.handle = cpu_to_le16(handle);
- dc.reason = 0x00;
-
- send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE,
- &dc, sizeof(dc));
- return;
- }
-
- dc.status = BT_HCI_ERR_SUCCESS;
- dc.handle = cpu_to_le16(handle);
- dc.reason = reason;
-
- remote = btdev->conn;
-
- btdev->conn = NULL;
- remote->conn = NULL;
-
- send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc));
- send_event(remote, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc));
-}
-
-static void name_request_complete(struct btdev *btdev,
- const uint8_t *bdaddr, uint8_t status)
-{
- struct bt_hci_evt_remote_name_req_complete nc;
-
- nc.status = status;
- memcpy(nc.bdaddr, bdaddr, 6);
- memset(nc.name, 0, 248);
-
- if (!status) {
- struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
-
- if (remote)
- memcpy(nc.name, remote->name, 248);
- else
- nc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
- }
-
- send_event(btdev, BT_HCI_EVT_REMOTE_NAME_REQUEST_COMPLETE,
- &nc, sizeof(nc));
-}
-
-static void remote_features_complete(struct btdev *btdev, uint16_t handle)
-{
- struct bt_hci_evt_remote_features_complete rfc;
-
- if (btdev->conn) {
- rfc.status = BT_HCI_ERR_SUCCESS;
- rfc.handle = cpu_to_le16(handle);
- memcpy(rfc.features, btdev->conn->features, 8);
- } else {
- rfc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
- rfc.handle = cpu_to_le16(handle);
- memset(rfc.features, 0, 8);
- }
-
- send_event(btdev, BT_HCI_EVT_REMOTE_FEATURES_COMPLETE,
- &rfc, sizeof(rfc));
-}
-
-static void remote_ext_features_complete(struct btdev *btdev, uint16_t handle,
- uint8_t page)
-{
- struct bt_hci_evt_remote_ext_features_complete refc;
-
- if (btdev->conn && page < 0x02) {
- refc.handle = cpu_to_le16(handle);
- refc.page = page;
- refc.max_page = 0x01;
-
- switch (page) {
- case 0x00:
- refc.status = BT_HCI_ERR_SUCCESS;
- memcpy(refc.features, btdev->conn->features, 8);
- break;
- case 0x01:
- refc.status = BT_HCI_ERR_SUCCESS;
- memset(refc.features, 0, 8);
- break;
- default:
- refc.status = BT_HCI_ERR_INVALID_PARAMETERS;
- memset(refc.features, 0, 8);
- break;
- }
- } else {
- refc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
- refc.handle = cpu_to_le16(handle);
- refc.page = page;
- refc.max_page = 0x01;
- memset(refc.features, 0, 8);
- }
-
- send_event(btdev, BT_HCI_EVT_REMOTE_EXT_FEATURES_COMPLETE,
- &refc, sizeof(refc));
-}
-
-static void remote_version_complete(struct btdev *btdev, uint16_t handle)
-{
- struct bt_hci_evt_remote_version_complete rvc;
-
- if (btdev->conn) {
- rvc.status = BT_HCI_ERR_SUCCESS;
- rvc.handle = cpu_to_le16(handle);
- rvc.lmp_ver = btdev->conn->version;
- rvc.manufacturer = cpu_to_le16(btdev->conn->manufacturer);
- rvc.lmp_subver = cpu_to_le16(btdev->conn->revision);
- } else {
- rvc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
- rvc.handle = cpu_to_le16(handle);
- rvc.lmp_ver = 0x00;
- rvc.manufacturer = cpu_to_le16(0);
- rvc.lmp_subver = cpu_to_le16(0);
- }
-
- send_event(btdev, BT_HCI_EVT_REMOTE_VERSION_COMPLETE,
- &rvc, sizeof(rvc));
-}
-
-static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
-{
- const struct bt_hci_cmd_hdr *hdr = data;
- const struct bt_hci_cmd_create_conn *cc;
- const struct bt_hci_cmd_disconnect *dc;
- const struct bt_hci_cmd_create_conn_cancel *ccc;
- const struct bt_hci_cmd_accept_conn_request *acr;
- const struct bt_hci_cmd_reject_conn_request *rcr;
- const struct bt_hci_cmd_remote_name_request *rnr;
- const struct bt_hci_cmd_remote_name_request_cancel *rnrc;
- const struct bt_hci_cmd_read_remote_features *rrf;
- const struct bt_hci_cmd_read_remote_ext_features *rref;
- const struct bt_hci_cmd_read_remote_version *rrv;
- const struct bt_hci_cmd_write_default_link_policy *wdlp;
- const struct bt_hci_cmd_set_event_mask *sem;
- const struct bt_hci_cmd_set_event_filter *sef;
- const struct bt_hci_cmd_write_local_name *wln;
- const struct bt_hci_cmd_write_conn_accept_timeout *wcat;
- const struct bt_hci_cmd_write_page_timeout *wpt;
- const struct bt_hci_cmd_write_scan_enable *wse;
- const struct bt_hci_cmd_write_auth_enable *wae;
- const struct bt_hci_cmd_write_class_of_dev *wcod;
- const struct bt_hci_cmd_write_voice_setting *wvs;
- const struct bt_hci_cmd_write_inquiry_mode *wim;
- const struct bt_hci_cmd_write_afh_assess_mode *waam;
- const struct bt_hci_cmd_write_ext_inquiry_rsp *weir;
- const struct bt_hci_cmd_write_simple_pairing_mode *wspm;
- const struct bt_hci_cmd_write_le_host_supported *wlhs;
- const struct bt_hci_cmd_le_set_event_mask *lsem;
- struct bt_hci_rsp_read_default_link_policy rdlp;
- struct bt_hci_rsp_read_stored_link_key rslk;
- struct bt_hci_rsp_write_stored_link_key wslk;
- struct bt_hci_rsp_delete_stored_link_key dslk;
- struct bt_hci_rsp_read_local_name rln;
- struct bt_hci_rsp_read_conn_accept_timeout rcat;
- struct bt_hci_rsp_read_page_timeout rpt;
- struct bt_hci_rsp_read_scan_enable rse;
- struct bt_hci_rsp_read_auth_enable rae;
- struct bt_hci_rsp_read_class_of_dev rcod;
- struct bt_hci_rsp_read_voice_setting rvs;
- struct bt_hci_rsp_read_inquiry_mode rim;
- struct bt_hci_rsp_read_afh_assess_mode raam;
- struct bt_hci_rsp_read_ext_inquiry_rsp reir;
- struct bt_hci_rsp_read_simple_pairing_mode rspm;
- struct bt_hci_rsp_read_inquiry_rsp_tx_power rirtp;
- struct bt_hci_rsp_read_le_host_supported rlhs;
- struct bt_hci_rsp_read_local_version rlv;
- struct bt_hci_rsp_read_local_commands rlc;
- struct bt_hci_rsp_read_local_features rlf;
- struct bt_hci_rsp_read_local_ext_features rlef;
- struct bt_hci_rsp_read_buffer_size rbs;
- struct bt_hci_rsp_read_country_code rcc;
- struct bt_hci_rsp_read_bd_addr rba;
- struct bt_hci_rsp_read_data_block_size rdbs;
- struct bt_hci_rsp_le_read_buffer_size lrbs;
- struct bt_hci_rsp_le_read_local_features lrlf;
- struct bt_hci_rsp_le_read_supported_states lrss;
- uint16_t opcode;
- uint8_t status, page;
-
- if (len < sizeof(*hdr))
- return;
-
- opcode = le16_to_cpu(hdr->opcode);
-
- switch (opcode) {
- case BT_HCI_CMD_INQUIRY:
- cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- inquiry_complete(btdev, BT_HCI_ERR_SUCCESS);
- break;
-
- case BT_HCI_CMD_INQUIRY_CANCEL:
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_CREATE_CONN:
- cc = data + sizeof(*hdr);
- cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- conn_request(btdev, cc->bdaddr);
- break;
-
- case BT_HCI_CMD_DISCONNECT:
- dc = data + sizeof(*hdr);
- cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- disconnect_complete(btdev, le16_to_cpu(dc->handle), dc->reason);
- break;
-
- case BT_HCI_CMD_CREATE_CONN_CANCEL:
- ccc = data + sizeof(*hdr);
- cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- conn_complete(btdev, ccc->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
- break;
-
- case BT_HCI_CMD_ACCEPT_CONN_REQUEST:
- acr = data + sizeof(*hdr);
- cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- conn_complete(btdev, acr->bdaddr, BT_HCI_ERR_SUCCESS);
- break;
-
- case BT_HCI_CMD_REJECT_CONN_REQUEST:
- rcr = data + sizeof(*hdr);
- cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- conn_complete(btdev, rcr->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
- break;
-
- case BT_HCI_CMD_REMOTE_NAME_REQUEST:
- rnr = data + sizeof(*hdr);
- cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- name_request_complete(btdev, rnr->bdaddr, BT_HCI_ERR_SUCCESS);
- break;
-
- case BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL:
- rnrc = data + sizeof(*hdr);
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- name_request_complete(btdev, rnrc->bdaddr,
- BT_HCI_ERR_UNKNOWN_CONN_ID);
- break;
-
- case BT_HCI_CMD_READ_REMOTE_FEATURES:
- rrf = data + sizeof(*hdr);
- cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- remote_features_complete(btdev, le16_to_cpu(rrf->handle));
- break;
-
- case BT_HCI_CMD_READ_REMOTE_EXT_FEATURES:
- rref = data + sizeof(*hdr);
- cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- remote_ext_features_complete(btdev, le16_to_cpu(rref->handle),
- rref->page);
- break;
-
- case BT_HCI_CMD_READ_REMOTE_VERSION:
- rrv = data + sizeof(*hdr);
- cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
- remote_version_complete(btdev, le16_to_cpu(rrv->handle));
- break;
-
- case BT_HCI_CMD_READ_DEFAULT_LINK_POLICY:
- rdlp.status = BT_HCI_ERR_SUCCESS;
- rdlp.policy = cpu_to_le16(btdev->default_link_policy);
- cmd_complete(btdev, opcode, &rdlp, sizeof(rdlp));
- break;
-
- case BT_HCI_CMD_WRITE_DEFAULT_LINK_POLICY:
- wdlp = data + sizeof(*hdr);
- btdev->default_link_policy = le16_to_cpu(wdlp->policy);
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_SET_EVENT_MASK:
- sem = data + sizeof(*hdr);
- memcpy(btdev->event_mask, sem->mask, 8);
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_RESET:
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_SET_EVENT_FILTER:
- sef = data + sizeof(*hdr);
- btdev->event_filter = sef->type;
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_STORED_LINK_KEY:
- rslk.status = BT_HCI_ERR_SUCCESS;
- rslk.max_num_keys = cpu_to_le16(0);
- rslk.num_keys = cpu_to_le16(0);
- cmd_complete(btdev, opcode, &rslk, sizeof(rslk));
- break;
-
- case BT_HCI_CMD_WRITE_STORED_LINK_KEY:
- wslk.status = BT_HCI_ERR_SUCCESS;
- wslk.num_keys = 0;
- cmd_complete(btdev, opcode, &wslk, sizeof(wslk));
- break;
-
- case BT_HCI_CMD_DELETE_STORED_LINK_KEY:
- dslk.status = BT_HCI_ERR_SUCCESS;
- dslk.num_keys = cpu_to_le16(0);
- cmd_complete(btdev, opcode, &dslk, sizeof(dslk));
- break;
-
- case BT_HCI_CMD_WRITE_LOCAL_NAME:
- wln = data + sizeof(*hdr);
- memcpy(btdev->name, wln->name, 248);
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_LOCAL_NAME:
- rln.status = BT_HCI_ERR_SUCCESS;
- memcpy(rln.name, btdev->name, 248);
- cmd_complete(btdev, opcode, &rln, sizeof(rln));
- break;
-
- case BT_HCI_CMD_READ_CONN_ACCEPT_TIMEOUT:
- rcat.status = BT_HCI_ERR_SUCCESS;
- rcat.timeout = cpu_to_le16(btdev->conn_accept_timeout);
- cmd_complete(btdev, opcode, &rcat, sizeof(rcat));
- break;
-
- case BT_HCI_CMD_WRITE_CONN_ACCEPT_TIMEOUT:
- wcat = data + sizeof(*hdr);
- btdev->conn_accept_timeout = le16_to_cpu(wcat->timeout);
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_PAGE_TIMEOUT:
- rpt.status = BT_HCI_ERR_SUCCESS;
- rpt.timeout = cpu_to_le16(btdev->page_timeout);
- cmd_complete(btdev, opcode, &rpt, sizeof(rpt));
- break;
-
- case BT_HCI_CMD_WRITE_PAGE_TIMEOUT:
- wpt = data + sizeof(*hdr);
- btdev->page_timeout = le16_to_cpu(wpt->timeout);
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_SCAN_ENABLE:
- rse.status = BT_HCI_ERR_SUCCESS;
- rse.enable = btdev->scan_enable;
- cmd_complete(btdev, opcode, &rse, sizeof(rse));
- break;
-
- case BT_HCI_CMD_WRITE_SCAN_ENABLE:
- wse = data + sizeof(*hdr);
- btdev->scan_enable = wse->enable;
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_AUTH_ENABLE:
- rae.status = BT_HCI_ERR_SUCCESS;
- rae.enable = btdev->auth_enable;
- cmd_complete(btdev, opcode, &rae, sizeof(rae));
- break;
-
- case BT_HCI_CMD_WRITE_AUTH_ENABLE:
- wae = data + sizeof(*hdr);
- btdev->auth_enable = wae->enable;
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_CLASS_OF_DEV:
- rcod.status = BT_HCI_ERR_SUCCESS;
- memcpy(rcod.dev_class, btdev->dev_class, 3);
- cmd_complete(btdev, opcode, &rcod, sizeof(rcod));
- break;
-
- case BT_HCI_CMD_WRITE_CLASS_OF_DEV:
- wcod = data + sizeof(*hdr);
- memcpy(btdev->dev_class, wcod->dev_class, 3);
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_VOICE_SETTING:
- rvs.status = BT_HCI_ERR_SUCCESS;
- rvs.setting = cpu_to_le16(btdev->voice_setting);
- cmd_complete(btdev, opcode, &rvs, sizeof(rvs));
- break;
-
- case BT_HCI_CMD_WRITE_VOICE_SETTING:
- wvs = data + sizeof(*hdr);
- btdev->voice_setting = le16_to_cpu(wvs->setting);
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_INQUIRY_MODE:
- rim.status = BT_HCI_ERR_SUCCESS;
- rim.mode = btdev->inquiry_mode;
- cmd_complete(btdev, opcode, &rim, sizeof(rim));
- break;
-
- case BT_HCI_CMD_WRITE_INQUIRY_MODE:
- wim = data + sizeof(*hdr);
- btdev->inquiry_mode = wim->mode;
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_AFH_ASSESS_MODE:
- raam.status = BT_HCI_ERR_SUCCESS;
- raam.mode = btdev->afh_assess_mode;
- cmd_complete(btdev, opcode, &raam, sizeof(raam));
- break;
-
- case BT_HCI_CMD_WRITE_AFH_ASSESS_MODE:
- waam = data + sizeof(*hdr);
- btdev->afh_assess_mode = waam->mode;
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_EXT_INQUIRY_RSP:
- reir.status = BT_HCI_ERR_SUCCESS;
- reir.fec = btdev->ext_inquiry_fec;
- memcpy(reir.data, btdev->ext_inquiry_rsp, 240);
- cmd_complete(btdev, opcode, &reir, sizeof(reir));
- break;
-
- case BT_HCI_CMD_WRITE_EXT_INQUIRY_RSP:
- weir = data + sizeof(*hdr);
- btdev->ext_inquiry_fec = weir->fec;
- memcpy(btdev->ext_inquiry_rsp, weir->data, 240);
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE:
- rspm.status = BT_HCI_ERR_SUCCESS;
- rspm.mode = btdev->simple_pairing_mode;
- cmd_complete(btdev, opcode, &rspm, sizeof(rspm));
- break;
-
- case BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE:
- wspm = data + sizeof(*hdr);
- btdev->simple_pairing_mode = wspm->mode;
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_INQUIRY_RSP_TX_POWER:
- rirtp.status = BT_HCI_ERR_SUCCESS;
- rirtp.level = 0;
- cmd_complete(btdev, opcode, &rirtp, sizeof(rirtp));
- break;
-
- case BT_HCI_CMD_READ_LE_HOST_SUPPORTED:
- rlhs.status = BT_HCI_ERR_SUCCESS;
- rlhs.supported = btdev->le_supported;
- rlhs.simultaneous = btdev->le_simultaneous;
- cmd_complete(btdev, opcode, &rlhs, sizeof(rlhs));
- break;
-
- case BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED:
- wlhs = data + sizeof(*hdr);
- btdev->le_supported = wlhs->supported;
- btdev->le_simultaneous = wlhs->simultaneous;
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_READ_LOCAL_VERSION:
- rlv.status = BT_HCI_ERR_SUCCESS;
- rlv.hci_ver = btdev->version;
- rlv.hci_rev = cpu_to_le16(btdev->revision);
- rlv.lmp_ver = btdev->version;
- rlv.manufacturer = cpu_to_le16(btdev->manufacturer);
- rlv.lmp_subver = cpu_to_le16(btdev->revision);
- cmd_complete(btdev, opcode, &rlv, sizeof(rlv));
- break;
-
- case BT_HCI_CMD_READ_LOCAL_COMMANDS:
- rlc.status = BT_HCI_ERR_SUCCESS;
- memcpy(rlc.commands, btdev->commands, 64);
- cmd_complete(btdev, opcode, &rlc, sizeof(rlc));
- break;
-
- case BT_HCI_CMD_READ_LOCAL_FEATURES:
- rlf.status = BT_HCI_ERR_SUCCESS;
- memcpy(rlf.features, btdev->features, 8);
- cmd_complete(btdev, opcode, &rlf, sizeof(rlf));
- break;
-
- case BT_HCI_CMD_READ_LOCAL_EXT_FEATURES:
- page = ((const uint8_t *) data)[sizeof(*hdr)];
- switch (page) {
- case 0x00:
- rlef.status = BT_HCI_ERR_SUCCESS;
- rlef.page = 0x00;
- rlef.max_page = 0x01;
- memcpy(rlef.features, btdev->features, 8);
- break;
- case 0x01:
- rlef.status = BT_HCI_ERR_SUCCESS;
- rlef.page = 0x01;
- rlef.max_page = 0x01;
- memset(rlef.features, 0, 8);
- if (btdev->simple_pairing_mode)
- rlef.features[0] |= 0x01;
- if (btdev->le_supported)
- rlef.features[0] |= 0x02;
- if (btdev->le_simultaneous)
- rlef.features[0] |= 0x04;
- break;
- default:
- rlef.status = BT_HCI_ERR_INVALID_PARAMETERS;
- rlef.page = page;
- rlef.max_page = 0x01;
- memset(rlef.features, 0, 8);
- break;
- }
- cmd_complete(btdev, opcode, &rlef, sizeof(rlef));
- break;
-
- case BT_HCI_CMD_READ_BUFFER_SIZE:
- rbs.status = BT_HCI_ERR_SUCCESS;
- rbs.acl_mtu = cpu_to_le16(btdev->acl_mtu);
- rbs.sco_mtu = 0;
- rbs.acl_max_pkt = cpu_to_le16(btdev->acl_max_pkt);
- rbs.sco_max_pkt = cpu_to_le16(0);
- cmd_complete(btdev, opcode, &rbs, sizeof(rbs));
- break;
-
- case BT_HCI_CMD_READ_COUNTRY_CODE:
- rcc.status = BT_HCI_ERR_SUCCESS;
- rcc.code = btdev->country_code;
- cmd_complete(btdev, opcode, &rcc, sizeof(rcc));
- break;
-
- case BT_HCI_CMD_READ_BD_ADDR:
- rba.status = BT_HCI_ERR_SUCCESS;
- memcpy(rba.bdaddr, btdev->bdaddr, 6);
- cmd_complete(btdev, opcode, &rba, sizeof(rba));
- break;
-
- case BT_HCI_CMD_READ_DATA_BLOCK_SIZE:
- rdbs.status = BT_HCI_ERR_SUCCESS;
- rdbs.max_acl_len = cpu_to_le16(btdev->acl_mtu);
- rdbs.block_len = cpu_to_le16(btdev->acl_mtu);
- rdbs.num_blocks = cpu_to_le16(btdev->acl_max_pkt);
- cmd_complete(btdev, opcode, &rdbs, sizeof(rdbs));
- break;
-
- case BT_HCI_CMD_LE_SET_EVENT_MASK:
- lsem = data + sizeof(*hdr);
- memcpy(btdev->le_event_mask, lsem->mask, 8);
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_LE_READ_BUFFER_SIZE:
- lrbs.status = BT_HCI_ERR_SUCCESS;
- lrbs.le_mtu = cpu_to_le16(btdev->acl_mtu);
- lrbs.le_max_pkt = btdev->acl_max_pkt;
- cmd_complete(btdev, opcode, &lrbs, sizeof(lrbs));
- break;
-
- case BT_HCI_CMD_LE_READ_LOCAL_FEATURES:
- lrlf.status = BT_HCI_ERR_SUCCESS;
- memcpy(lrlf.features, btdev->le_features, 8);
- cmd_complete(btdev, opcode, &lrlf, sizeof(lrlf));
- break;
-
- case BT_HCI_CMD_LE_SET_SCAN_PARAMETERS:
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_LE_SET_SCAN_ENABLE:
- status = BT_HCI_ERR_SUCCESS;
- cmd_complete(btdev, opcode, &status, sizeof(status));
- break;
-
- case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
- lrss.status = BT_HCI_ERR_SUCCESS;
- memcpy(lrss.states, btdev->le_states, 8);
- cmd_complete(btdev, opcode, &lrss, sizeof(lrss));
- break;
-
- default:
- printf("Unsupported command 0x%4.4x\n", opcode);
- hexdump(data, len);
- cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, opcode);
- break;
- }
-}
-
-void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
-{
- uint8_t pkt_type;
-
- if (!btdev)
- return;
-
- if (len < 1)
- return;
-
- pkt_type = ((const uint8_t *) data)[0];
-
- switch (pkt_type) {
- case BT_H4_CMD_PKT:
- process_cmd(btdev, data + 1, len - 1);
- break;
- case BT_H4_ACL_PKT:
- if (btdev->conn)
- send_packet(btdev->conn, data, len);
- num_completed_packets(btdev);
- break;
- default:
- printf("Unsupported packet 0x%2.2x\n", pkt_type);
- break;
- }
-}
diff --git a/emulator/btdev.h b/emulator/btdev.h
deleted file mode 100644
index 7b211a2..0000000
--- a/emulator/btdev.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2012 Intel Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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
- *
- */
-
-#include <stdint.h>
-
-typedef void (*btdev_send_func) (const void *data, uint16_t len,
- void *user_data);
-
-struct btdev;
-
-struct btdev *btdev_create(uint16_t id);
-void btdev_destroy(struct btdev *btdev);
-
-void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
- void *user_data);
-
-void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len);
diff --git a/emulator/main.c b/emulator/main.c
deleted file mode 100644
index 125460d..0000000
--- a/emulator/main.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2012 Intel Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 <stdio.h>
-
-#include "mainloop.h"
-#include "server.h"
-#include "vhci.h"
-
-static void signal_callback(int signum, void *user_data)
-{
- switch (signum) {
- case SIGINT:
- case SIGTERM:
- mainloop_quit();
- break;
- }
-}
-
-int main(int argc, char *argv[])
-{
- struct vhci *vhci;
- struct server *server;
- sigset_t mask;
-
- mainloop_init();
-
- sigemptyset(&mask);
- sigaddset(&mask, SIGINT);
- sigaddset(&mask, SIGTERM);
-
- mainloop_set_signal(&mask, signal_callback, NULL, NULL);
-
- vhci = vhci_open(VHCI_TYPE_BREDR, 0x23);
- if (!vhci) {
- fprintf(stderr, "Failed to open Virtual HCI device\n");
- return 1;
- }
-
- server = server_open_unix("/tmp/bt-server-bredr", 0x42);
- if (!server) {
- fprintf(stderr, "Failed to open server channel\n");
- vhci_close(vhci);
- return 1;
- }
-
- return mainloop_run();
-}
diff --git a/emulator/server.c b/emulator/server.c
deleted file mode 100644
index 1ff9904..0000000
--- a/emulator/server.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2012 Intel Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-
-#include "mainloop.h"
-#include "btdev.h"
-#include "server.h"
-
-struct server {
- uint16_t id;
- int fd;
-};
-
-struct client {
- int fd;
- struct btdev *btdev;
- uint8_t *pkt_data;
- uint8_t pkt_type;
- uint16_t pkt_expect;
- uint16_t pkt_len;
- uint16_t pkt_offset;
-};
-
-static void server_destroy(void *user_data)
-{
- struct server *server = user_data;
-
- close(server->fd);
-
- free(server);
-}
-
-static void client_destroy(void *user_data)
-{
- struct client *client = user_data;
-
- btdev_destroy(client->btdev);
-
- close(client->fd);
-
- free(client);
-}
-
-static void client_write_callback(const void *data, uint16_t len,
- void *user_data)
-{
- struct client *client = user_data;
- ssize_t written;
-
- written = send(client->fd, data, len, MSG_DONTWAIT);
- if (written < 0)
- return;
-}
-
-static void client_read_callback(int fd, uint32_t events, void *user_data)
-{
- struct client *client = user_data;
- static uint8_t buf[4096];
- uint8_t *ptr = buf;
- ssize_t len;
- uint16_t count;
-
- if (events & (EPOLLERR | EPOLLHUP))
- return;
-
-again:
- len = recv(fd, buf + client->pkt_offset,
- sizeof(buf) - client->pkt_offset, MSG_DONTWAIT);
- if (len < 0) {
- if (errno == EAGAIN)
- goto again;
- return;
- }
-
- count = client->pkt_offset + len;
-
- while (count > 0) {
- hci_command_hdr *cmd_hdr;
-
- if (!client->pkt_data) {
- client->pkt_type = ptr[0];
-
- switch (client->pkt_type) {
- case HCI_COMMAND_PKT:
- if (count < HCI_COMMAND_HDR_SIZE + 1) {
- client->pkt_offset += len;
- return;
- }
- cmd_hdr = (hci_command_hdr *) (ptr + 1);
- client->pkt_expect = HCI_COMMAND_HDR_SIZE +
- cmd_hdr->plen + 1;
- client->pkt_data = malloc(client->pkt_expect);
- client->pkt_len = 0;
- break;
- default:
- printf("packet error\n");
- return;
- }
-
- client->pkt_offset = 0;
- }
-
- if (count >= client->pkt_expect) {
- memcpy(client->pkt_data + client->pkt_len,
- ptr, client->pkt_expect);
- ptr += client->pkt_expect;
- count -= client->pkt_expect;
-
- btdev_receive_h4(client->btdev, client->pkt_data,
- client->pkt_len + client->pkt_expect);
-
- free(client->pkt_data);
- client->pkt_data = NULL;
- } else {
- memcpy(client->pkt_data + client->pkt_len, ptr, count);
- client->pkt_len += count;
- client->pkt_expect -= count;
- count = 0;
- }
- }
-}
-
-static int accept_client(int fd)
-{
- struct sockaddr_un addr;
- socklen_t len;
- int nfd;
-
- memset(&addr, 0, sizeof(addr));
- len = sizeof(addr);
-
- if (getsockname(fd, (struct sockaddr *) &addr, &len) < 0) {
- perror("Failed to get socket name");
- return -1;
- }
-
- printf("Request for %s\n", addr.sun_path);
-
- nfd = accept(fd, (struct sockaddr *) &addr, &len);
- if (nfd < 0) {
- perror("Failed to accept client socket");
- return -1;
- }
-
- return nfd;
-}
-
-static void server_accept_callback(int fd, uint32_t events, void *user_data)
-{
- struct server *server = user_data;
- struct client *client;
-
- if (events & (EPOLLERR | EPOLLHUP))
- return;
-
- client = malloc(sizeof(*client));
- if (!client)
- return;
-
- memset(client, 0, sizeof(*client));
-
- client->fd = accept_client(server->fd);
- if (client->fd < 0) {
- free(client);
- return;
- }
-
- client->btdev = btdev_create(server->id);
- if (!client->btdev) {
- close(client->fd);
- free(client);
- return;
- }
-
- btdev_set_send_handler(client->btdev, client_write_callback, client);
-
- if (mainloop_add_fd(client->fd, EPOLLIN, client_read_callback,
- client, client_destroy) < 0) {
- btdev_destroy(client->btdev);
- close(client->fd);
- free(client);
- }
-}
-
-static int open_server(const char *path)
-{
- struct sockaddr_un addr;
- int fd;
-
- unlink(path);
-
- fd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
- perror("Failed to open server socket");
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, path);
-
- if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("Failed to bind server socket");
- close(fd);
- return -1;
- }
-
- if (listen(fd, 5) < 0) {
- perror("Failed to listen server socket");
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-struct server *server_open_unix(const char *path, uint16_t id)
-{
- struct server *server;
-
- server = malloc(sizeof(*server));
- if (!server)
- return NULL;
-
- memset(server, 0, sizeof(*server));
- server->id = id;
-
- server->fd = open_server(path);
- if (server->fd < 0) {
- free(server);
- return NULL;
- }
-
- if (mainloop_add_fd(server->fd, EPOLLIN, server_accept_callback,
- server, server_destroy) < 0) {
- close(server->fd);
- free(server);
- return NULL;
- }
-
- return server;
-}
-
-void server_close(struct server *server)
-{
- if (!server)
- return;
-
- mainloop_remove_fd(server->fd);
-}
diff --git a/emulator/server.h b/emulator/server.h
deleted file mode 100644
index 836db5f..0000000
--- a/emulator/server.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2012 Intel Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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
- *
- */
-
-#include <stdint.h>
-
-struct server;
-
-struct server *server_open_unix(const char *path, uint16_t id);
-void server_close(struct server *server);
diff --git a/emulator/vhci.c b/emulator/vhci.c
deleted file mode 100644
index 940e562..0000000
--- a/emulator/vhci.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2012 Intel Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "mainloop.h"
-#include "btdev.h"
-#include "vhci.h"
-
-struct vhci {
- enum vhci_type type;
- int fd;
- struct btdev *btdev;
-};
-
-static void vhci_destroy(void *user_data)
-{
- struct vhci *vhci = user_data;
-
- btdev_destroy(vhci->btdev);
-
- close(vhci->fd);
-
- free(vhci);
-}
-
-static void vhci_write_callback(const void *data, uint16_t len, void *user_data)
-{
- struct vhci *vhci = user_data;
- ssize_t written;
-
- written = write(vhci->fd, data, len);
- if (written < 0)
- return;
-}
-
-static void vhci_read_callback(int fd, uint32_t events, void *user_data)
-{
- struct vhci *vhci = user_data;
- unsigned char buf[4096];
- ssize_t len;
-
- if (events & (EPOLLERR | EPOLLHUP))
- return;
-
- len = read(vhci->fd, buf, sizeof(buf));
- if (len < 0)
- return;
-
- btdev_receive_h4(vhci->btdev, buf, len);
-}
-
-struct vhci *vhci_open(enum vhci_type type, uint16_t id)
-{
- struct vhci *vhci;
-
- switch (type) {
- case VHCI_TYPE_BREDR:
- break;
- case VHCI_TYPE_AMP:
- return NULL;
- }
-
- vhci = malloc(sizeof(*vhci));
- if (!vhci)
- return NULL;
-
- memset(vhci, 0, sizeof(*vhci));
- vhci->type = type;
-
- vhci->fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
- if (vhci->fd < 0) {
- free(vhci);
- return NULL;
- }
-
- vhci->btdev = btdev_create(id);
- if (!vhci->btdev) {
- close(vhci->fd);
- free(vhci);
- return NULL;
- }
-
- btdev_set_send_handler(vhci->btdev, vhci_write_callback, vhci);
-
- if (mainloop_add_fd(vhci->fd, EPOLLIN, vhci_read_callback,
- vhci, vhci_destroy) < 0) {
- btdev_destroy(vhci->btdev);
- close(vhci->fd);
- free(vhci);
- return NULL;
- }
-
- return vhci;
-}
-
-void vhci_close(struct vhci *vhci)
-{
- if (!vhci)
- return;
-
- mainloop_remove_fd(vhci->fd);
-}
diff --git a/emulator/vhci.h b/emulator/vhci.h
deleted file mode 100644
index 4abb183..0000000
--- a/emulator/vhci.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2012 Intel Corporation
- * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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
- *
- */
-
-#include <stdint.h>
-
-enum vhci_type {
- VHCI_TYPE_BREDR = 0,
- VHCI_TYPE_AMP = 1,
-};
-
-struct vhci;
-
-struct vhci *vhci_open(enum vhci_type type, uint16_t id);
-void vhci_close(struct vhci *vhci);
diff --git a/tools/emulator/btdev.c b/tools/emulator/btdev.c
new file mode 100644
index 0000000..7d4517a
--- /dev/null
+++ b/tools/emulator/btdev.c
@@ -0,0 +1,1076 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt.h"
+#include "btdev.h"
+
+#define le16_to_cpu(val) (val)
+#define cpu_to_le16(val) (val)
+
+struct btdev {
+ struct btdev *conn;
+
+ btdev_send_func send_handler;
+ void *send_data;
+
+ uint16_t manufacturer;
+ uint8_t version;
+ uint16_t revision;
+ uint8_t commands[64];
+ uint8_t features[8];
+ uint16_t acl_mtu;
+ uint16_t acl_max_pkt;
+ uint8_t country_code;
+ uint8_t bdaddr[6];
+ uint8_t le_features[8];
+ uint8_t le_states[8];
+
+ uint16_t default_link_policy;
+ uint8_t event_mask[8];
+ uint8_t event_filter;
+ uint8_t name[248];
+ uint8_t dev_class[3];
+ uint16_t voice_setting;
+ uint16_t conn_accept_timeout;
+ uint16_t page_timeout;
+ uint8_t scan_enable;
+ uint8_t auth_enable;
+ uint8_t inquiry_mode;
+ uint8_t afh_assess_mode;
+ uint8_t ext_inquiry_fec;
+ uint8_t ext_inquiry_rsp[240];
+ uint8_t simple_pairing_mode;
+ uint8_t le_supported;
+ uint8_t le_simultaneous;
+ uint8_t le_event_mask[8];
+};
+
+#define MAX_BTDEV_ENTRIES 16
+
+static struct btdev *btdev_list[MAX_BTDEV_ENTRIES] = { };
+
+static inline int add_btdev(struct btdev *btdev)
+{
+ int i, index = -1;
+
+ for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+ if (btdev_list[i] == NULL) {
+ index = i;
+ btdev_list[index] = btdev;
+ break;
+ }
+ }
+
+ return index;
+}
+
+static inline int del_btdev(struct btdev *btdev)
+{
+ int i, index = -1;
+
+ for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+ if (btdev_list[i] == btdev) {
+ index = i;
+ btdev_list[index] = NULL;
+ break;
+ }
+ }
+
+ return index;
+}
+
+static inline struct btdev *find_btdev_by_bdaddr(const uint8_t *bdaddr)
+{
+ int i;
+
+ for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+ if (btdev_list[i] && !memcmp(btdev_list[i]->bdaddr, bdaddr, 6))
+ return btdev_list[i];
+ }
+
+ return NULL;
+}
+
+static void hexdump(const unsigned char *buf, uint16_t len)
+{
+ static const char hexdigits[] = "0123456789abcdef";
+ char str[68];
+ uint16_t i;
+
+ if (!len)
+ return;
+
+ for (i = 0; i < len; i++) {
+ str[((i % 16) * 3) + 0] = hexdigits[buf[i] >> 4];
+ str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf];
+ str[((i % 16) * 3) + 2] = ' ';
+ str[(i % 16) + 49] = isprint(buf[i]) ? buf[i] : '.';
+
+ if ((i + 1) % 16 == 0) {
+ str[47] = ' ';
+ str[48] = ' ';
+ str[65] = '\0';
+ printf("%-12c%s\n", ' ', str);
+ str[0] = ' ';
+ }
+ }
+
+ if (i % 16 > 0) {
+ uint16_t j;
+ for (j = (i % 16); j < 16; j++) {
+ str[(j * 3) + 0] = ' ';
+ str[(j * 3) + 1] = ' ';
+ str[(j * 3) + 2] = ' ';
+ str[j + 49] = ' ';
+ }
+ str[47] = ' ';
+ str[48] = ' ';
+ str[65] = '\0';
+ printf("%-12c%s\n", ' ', str);
+ }
+}
+
+static void get_bdaddr(uint16_t id, uint8_t *bdaddr)
+{
+ bdaddr[0] = id & 0xff;
+ bdaddr[1] = id >> 8;
+ bdaddr[2] = 0x00;
+ bdaddr[3] = 0x01;
+ bdaddr[4] = 0xaa;
+ bdaddr[5] = 0x00;
+}
+
+struct btdev *btdev_create(uint16_t id)
+{
+ struct btdev *btdev;
+
+ btdev = malloc(sizeof(*btdev));
+ if (!btdev)
+ return NULL;
+
+ memset(btdev, 0, sizeof(*btdev));
+
+ btdev->manufacturer = 63;
+ btdev->version = 0x06;
+ btdev->revision = 0x0000;
+
+ btdev->features[0] |= 0x04; /* Encryption */
+ btdev->features[0] |= 0x20; /* Role switch */
+ btdev->features[0] |= 0x80; /* Sniff mode */
+ btdev->features[1] |= 0x08; /* SCO link */
+ btdev->features[3] |= 0x40; /* RSSI with inquiry results */
+ btdev->features[3] |= 0x80; /* Extended SCO link */
+ btdev->features[4] |= 0x08; /* AFH capable slave */
+ btdev->features[4] |= 0x10; /* AFH classification slave */
+ btdev->features[4] |= 0x40; /* LE Supported */
+ btdev->features[5] |= 0x02; /* Sniff subrating */
+ btdev->features[5] |= 0x04; /* Pause encryption */
+ btdev->features[5] |= 0x08; /* AFH capable master */
+ btdev->features[5] |= 0x10; /* AFH classification master */
+ btdev->features[6] |= 0x01; /* Extended Inquiry Response */
+ btdev->features[6] |= 0x02; /* Simultaneous LE and BR/EDR */
+ btdev->features[6] |= 0x08; /* Secure Simple Pairing */
+ btdev->features[6] |= 0x10; /* Encapsulated PDU */
+ btdev->features[6] |= 0x20; /* Erroneous Data Reporting */
+ btdev->features[6] |= 0x40; /* Non-flushable Packet Boundary Flag */
+ btdev->features[7] |= 0x01; /* Link Supervision Timeout Event */
+ btdev->features[7] |= 0x02; /* Inquiry TX Power Level */
+ btdev->features[7] |= 0x80; /* Extended features */
+
+ btdev->acl_mtu = 192;
+ btdev->acl_max_pkt = 1;
+
+ btdev->country_code = 0x00;
+
+ get_bdaddr(id, btdev->bdaddr);
+
+ add_btdev(btdev);
+
+ return btdev;
+}
+
+void btdev_destroy(struct btdev *btdev)
+{
+ if (!btdev)
+ return;
+
+ del_btdev(btdev);
+
+ free(btdev);
+}
+
+void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
+ void *user_data)
+{
+ if (!btdev)
+ return;
+
+ btdev->send_handler = handler;
+ btdev->send_data = user_data;
+}
+
+static void send_packet(struct btdev *btdev, const void *data, uint16_t len)
+{
+ if (!btdev->send_handler)
+ return;
+
+ btdev->send_handler(data, len, btdev->send_data);
+}
+
+static void send_event(struct btdev *btdev, uint8_t event,
+ const void *data, uint8_t len)
+{
+ struct bt_hci_evt_hdr *hdr;
+ uint16_t pkt_len;
+ void *pkt_data;
+
+ pkt_len = 1 + sizeof(*hdr) + len;
+
+ pkt_data = malloc(pkt_len);
+ if (!pkt_data)
+ return;
+
+ ((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
+
+ hdr = pkt_data + 1;
+ hdr->evt = event;
+ hdr->plen = len;
+
+ if (len > 0)
+ memcpy(pkt_data + 1 + sizeof(*hdr), data, len);
+
+ send_packet(btdev, pkt_data, pkt_len);
+
+ free(pkt_data);
+}
+
+static void cmd_complete(struct btdev *btdev, uint16_t opcode,
+ const void *data, uint8_t len)
+{
+ struct bt_hci_evt_hdr *hdr;
+ struct bt_hci_evt_cmd_complete *cc;
+ uint16_t pkt_len;
+ void *pkt_data;
+
+ pkt_len = 1 + sizeof(*hdr) + sizeof(*cc) + len;
+
+ pkt_data = malloc(pkt_len);
+ if (!pkt_data)
+ return;
+
+ ((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
+
+ hdr = pkt_data + 1;
+ hdr->evt = BT_HCI_EVT_CMD_COMPLETE;
+ hdr->plen = sizeof(*cc) + len;
+
+ cc = pkt_data + 1 + sizeof(*hdr);
+ cc->ncmd = 0x01;
+ cc->opcode = cpu_to_le16(opcode);
+
+ if (len > 0)
+ memcpy(pkt_data + 1 + sizeof(*hdr) + sizeof(*cc), data, len);
+
+ send_packet(btdev, pkt_data, pkt_len);
+
+ free(pkt_data);
+}
+
+static void cmd_status(struct btdev *btdev, uint8_t status, uint16_t opcode)
+{
+ struct bt_hci_evt_cmd_status cs;
+
+ cs.status = status;
+ cs.ncmd = 0x01;
+ cs.opcode = cpu_to_le16(opcode);
+
+ send_event(btdev, BT_HCI_EVT_CMD_STATUS, &cs, sizeof(cs));
+}
+
+static void num_completed_packets(struct btdev *btdev)
+{
+ if (btdev->conn) {
+ struct bt_hci_evt_num_completed_packets ncp;
+
+ ncp.num_handles = 1;
+ ncp.handle = cpu_to_le16(42);
+ ncp.count = cpu_to_le16(1);
+
+ send_event(btdev, BT_HCI_EVT_NUM_COMPLETED_PACKETS,
+ &ncp, sizeof(ncp));
+ }
+}
+
+static void inquiry_complete(struct btdev *btdev, uint8_t status)
+{
+ struct bt_hci_evt_inquiry_complete ic;
+ int i;
+
+ for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+ if (!btdev_list[i] || btdev_list[i] == btdev)
+ continue;
+
+ if (!(btdev_list[i]->scan_enable & 0x02))
+ continue;
+
+ if (btdev->inquiry_mode == 0x02 &&
+ btdev_list[i]->ext_inquiry_rsp[0]) {
+ struct bt_hci_evt_ext_inquiry_result ir;
+
+ ir.num_resp = 0x01;
+ memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+ memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+ ir.rssi = -60;
+ memcpy(ir.data, btdev_list[i]->ext_inquiry_rsp, 240);
+
+ send_event(btdev, BT_HCI_EVT_EXT_INQUIRY_RESULT,
+ &ir, sizeof(ir));
+ continue;
+ }
+
+ if (btdev->inquiry_mode > 0x00) {
+ struct bt_hci_evt_inquiry_result_with_rssi ir;
+
+ ir.num_resp = 0x01;
+ memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+ memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+ ir.rssi = -60;
+
+ send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI,
+ &ir, sizeof(ir));
+ } else {
+ struct bt_hci_evt_inquiry_result ir;
+
+ ir.num_resp = 0x01;
+ memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+ memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+
+ send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT,
+ &ir, sizeof(ir));
+ }
+ }
+
+ ic.status = status;
+
+ send_event(btdev, BT_HCI_EVT_INQUIRY_COMPLETE, &ic, sizeof(ic));
+}
+
+static void conn_complete(struct btdev *btdev,
+ const uint8_t *bdaddr, uint8_t status)
+{
+ struct bt_hci_evt_conn_complete cc;
+
+ if (!status) {
+ struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+ btdev->conn = remote;
+ remote->conn = btdev;
+
+ cc.status = status;
+ memcpy(cc.bdaddr, btdev->bdaddr, 6);
+ cc.encr_mode = 0x00;
+
+ cc.handle = cpu_to_le16(42);
+ cc.link_type = 0x01;
+
+ send_event(remote, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
+
+ cc.handle = cpu_to_le16(42);
+ cc.link_type = 0x01;
+ } else {
+ cc.handle = cpu_to_le16(0x0000);
+ cc.link_type = 0x01;
+ }
+
+ cc.status = status;
+ memcpy(cc.bdaddr, bdaddr, 6);
+ cc.encr_mode = 0x00;
+
+ send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
+}
+
+static void conn_request(struct btdev *btdev, const uint8_t *bdaddr)
+{
+ struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+ if (remote) {
+ if (remote->scan_enable & 0x01) {
+ struct bt_hci_evt_conn_request cr;
+
+ memcpy(cr.bdaddr, btdev->bdaddr, 6);
+ memcpy(cr.dev_class, btdev->dev_class, 3);
+ cr.link_type = 0x01;
+
+ send_event(remote, BT_HCI_EVT_CONN_REQUEST,
+ &cr, sizeof(cr));
+ } else
+ conn_complete(btdev, bdaddr, BT_HCI_ERR_PAGE_TIMEOUT);
+ } else
+ conn_complete(btdev, bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+}
+
+static void disconnect_complete(struct btdev *btdev, uint16_t handle,
+ uint8_t reason)
+{
+ struct bt_hci_evt_disconnect_complete dc;
+ struct btdev *remote;
+
+ if (!btdev) {
+ dc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ dc.handle = cpu_to_le16(handle);
+ dc.reason = 0x00;
+
+ send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE,
+ &dc, sizeof(dc));
+ return;
+ }
+
+ dc.status = BT_HCI_ERR_SUCCESS;
+ dc.handle = cpu_to_le16(handle);
+ dc.reason = reason;
+
+ remote = btdev->conn;
+
+ btdev->conn = NULL;
+ remote->conn = NULL;
+
+ send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc));
+ send_event(remote, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc));
+}
+
+static void name_request_complete(struct btdev *btdev,
+ const uint8_t *bdaddr, uint8_t status)
+{
+ struct bt_hci_evt_remote_name_req_complete nc;
+
+ nc.status = status;
+ memcpy(nc.bdaddr, bdaddr, 6);
+ memset(nc.name, 0, 248);
+
+ if (!status) {
+ struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+ if (remote)
+ memcpy(nc.name, remote->name, 248);
+ else
+ nc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ }
+
+ send_event(btdev, BT_HCI_EVT_REMOTE_NAME_REQUEST_COMPLETE,
+ &nc, sizeof(nc));
+}
+
+static void remote_features_complete(struct btdev *btdev, uint16_t handle)
+{
+ struct bt_hci_evt_remote_features_complete rfc;
+
+ if (btdev->conn) {
+ rfc.status = BT_HCI_ERR_SUCCESS;
+ rfc.handle = cpu_to_le16(handle);
+ memcpy(rfc.features, btdev->conn->features, 8);
+ } else {
+ rfc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ rfc.handle = cpu_to_le16(handle);
+ memset(rfc.features, 0, 8);
+ }
+
+ send_event(btdev, BT_HCI_EVT_REMOTE_FEATURES_COMPLETE,
+ &rfc, sizeof(rfc));
+}
+
+static void remote_ext_features_complete(struct btdev *btdev, uint16_t handle,
+ uint8_t page)
+{
+ struct bt_hci_evt_remote_ext_features_complete refc;
+
+ if (btdev->conn && page < 0x02) {
+ refc.handle = cpu_to_le16(handle);
+ refc.page = page;
+ refc.max_page = 0x01;
+
+ switch (page) {
+ case 0x00:
+ refc.status = BT_HCI_ERR_SUCCESS;
+ memcpy(refc.features, btdev->conn->features, 8);
+ break;
+ case 0x01:
+ refc.status = BT_HCI_ERR_SUCCESS;
+ memset(refc.features, 0, 8);
+ break;
+ default:
+ refc.status = BT_HCI_ERR_INVALID_PARAMETERS;
+ memset(refc.features, 0, 8);
+ break;
+ }
+ } else {
+ refc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ refc.handle = cpu_to_le16(handle);
+ refc.page = page;
+ refc.max_page = 0x01;
+ memset(refc.features, 0, 8);
+ }
+
+ send_event(btdev, BT_HCI_EVT_REMOTE_EXT_FEATURES_COMPLETE,
+ &refc, sizeof(refc));
+}
+
+static void remote_version_complete(struct btdev *btdev, uint16_t handle)
+{
+ struct bt_hci_evt_remote_version_complete rvc;
+
+ if (btdev->conn) {
+ rvc.status = BT_HCI_ERR_SUCCESS;
+ rvc.handle = cpu_to_le16(handle);
+ rvc.lmp_ver = btdev->conn->version;
+ rvc.manufacturer = cpu_to_le16(btdev->conn->manufacturer);
+ rvc.lmp_subver = cpu_to_le16(btdev->conn->revision);
+ } else {
+ rvc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+ rvc.handle = cpu_to_le16(handle);
+ rvc.lmp_ver = 0x00;
+ rvc.manufacturer = cpu_to_le16(0);
+ rvc.lmp_subver = cpu_to_le16(0);
+ }
+
+ send_event(btdev, BT_HCI_EVT_REMOTE_VERSION_COMPLETE,
+ &rvc, sizeof(rvc));
+}
+
+static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
+{
+ const struct bt_hci_cmd_hdr *hdr = data;
+ const struct bt_hci_cmd_create_conn *cc;
+ const struct bt_hci_cmd_disconnect *dc;
+ const struct bt_hci_cmd_create_conn_cancel *ccc;
+ const struct bt_hci_cmd_accept_conn_request *acr;
+ const struct bt_hci_cmd_reject_conn_request *rcr;
+ const struct bt_hci_cmd_remote_name_request *rnr;
+ const struct bt_hci_cmd_remote_name_request_cancel *rnrc;
+ const struct bt_hci_cmd_read_remote_features *rrf;
+ const struct bt_hci_cmd_read_remote_ext_features *rref;
+ const struct bt_hci_cmd_read_remote_version *rrv;
+ const struct bt_hci_cmd_write_default_link_policy *wdlp;
+ const struct bt_hci_cmd_set_event_mask *sem;
+ const struct bt_hci_cmd_set_event_filter *sef;
+ const struct bt_hci_cmd_write_local_name *wln;
+ const struct bt_hci_cmd_write_conn_accept_timeout *wcat;
+ const struct bt_hci_cmd_write_page_timeout *wpt;
+ const struct bt_hci_cmd_write_scan_enable *wse;
+ const struct bt_hci_cmd_write_auth_enable *wae;
+ const struct bt_hci_cmd_write_class_of_dev *wcod;
+ const struct bt_hci_cmd_write_voice_setting *wvs;
+ const struct bt_hci_cmd_write_inquiry_mode *wim;
+ const struct bt_hci_cmd_write_afh_assess_mode *waam;
+ const struct bt_hci_cmd_write_ext_inquiry_rsp *weir;
+ const struct bt_hci_cmd_write_simple_pairing_mode *wspm;
+ const struct bt_hci_cmd_write_le_host_supported *wlhs;
+ const struct bt_hci_cmd_le_set_event_mask *lsem;
+ struct bt_hci_rsp_read_default_link_policy rdlp;
+ struct bt_hci_rsp_read_stored_link_key rslk;
+ struct bt_hci_rsp_write_stored_link_key wslk;
+ struct bt_hci_rsp_delete_stored_link_key dslk;
+ struct bt_hci_rsp_read_local_name rln;
+ struct bt_hci_rsp_read_conn_accept_timeout rcat;
+ struct bt_hci_rsp_read_page_timeout rpt;
+ struct bt_hci_rsp_read_scan_enable rse;
+ struct bt_hci_rsp_read_auth_enable rae;
+ struct bt_hci_rsp_read_class_of_dev rcod;
+ struct bt_hci_rsp_read_voice_setting rvs;
+ struct bt_hci_rsp_read_inquiry_mode rim;
+ struct bt_hci_rsp_read_afh_assess_mode raam;
+ struct bt_hci_rsp_read_ext_inquiry_rsp reir;
+ struct bt_hci_rsp_read_simple_pairing_mode rspm;
+ struct bt_hci_rsp_read_inquiry_rsp_tx_power rirtp;
+ struct bt_hci_rsp_read_le_host_supported rlhs;
+ struct bt_hci_rsp_read_local_version rlv;
+ struct bt_hci_rsp_read_local_commands rlc;
+ struct bt_hci_rsp_read_local_features rlf;
+ struct bt_hci_rsp_read_local_ext_features rlef;
+ struct bt_hci_rsp_read_buffer_size rbs;
+ struct bt_hci_rsp_read_country_code rcc;
+ struct bt_hci_rsp_read_bd_addr rba;
+ struct bt_hci_rsp_read_data_block_size rdbs;
+ struct bt_hci_rsp_le_read_buffer_size lrbs;
+ struct bt_hci_rsp_le_read_local_features lrlf;
+ struct bt_hci_rsp_le_read_supported_states lrss;
+ uint16_t opcode;
+ uint8_t status, page;
+
+ if (len < sizeof(*hdr))
+ return;
+
+ opcode = le16_to_cpu(hdr->opcode);
+
+ switch (opcode) {
+ case BT_HCI_CMD_INQUIRY:
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+ inquiry_complete(btdev, BT_HCI_ERR_SUCCESS);
+ break;
+
+ case BT_HCI_CMD_INQUIRY_CANCEL:
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_CREATE_CONN:
+ cc = data + sizeof(*hdr);
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+ conn_request(btdev, cc->bdaddr);
+ break;
+
+ case BT_HCI_CMD_DISCONNECT:
+ dc = data + sizeof(*hdr);
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+ disconnect_complete(btdev, le16_to_cpu(dc->handle), dc->reason);
+ break;
+
+ case BT_HCI_CMD_CREATE_CONN_CANCEL:
+ ccc = data + sizeof(*hdr);
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+ conn_complete(btdev, ccc->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+ break;
+
+ case BT_HCI_CMD_ACCEPT_CONN_REQUEST:
+ acr = data + sizeof(*hdr);
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+ conn_complete(btdev, acr->bdaddr, BT_HCI_ERR_SUCCESS);
+ break;
+
+ case BT_HCI_CMD_REJECT_CONN_REQUEST:
+ rcr = data + sizeof(*hdr);
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+ conn_complete(btdev, rcr->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+ break;
+
+ case BT_HCI_CMD_REMOTE_NAME_REQUEST:
+ rnr = data + sizeof(*hdr);
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+ name_request_complete(btdev, rnr->bdaddr, BT_HCI_ERR_SUCCESS);
+ break;
+
+ case BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL:
+ rnrc = data + sizeof(*hdr);
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ name_request_complete(btdev, rnrc->bdaddr,
+ BT_HCI_ERR_UNKNOWN_CONN_ID);
+ break;
+
+ case BT_HCI_CMD_READ_REMOTE_FEATURES:
+ rrf = data + sizeof(*hdr);
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+ remote_features_complete(btdev, le16_to_cpu(rrf->handle));
+ break;
+
+ case BT_HCI_CMD_READ_REMOTE_EXT_FEATURES:
+ rref = data + sizeof(*hdr);
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+ remote_ext_features_complete(btdev, le16_to_cpu(rref->handle),
+ rref->page);
+ break;
+
+ case BT_HCI_CMD_READ_REMOTE_VERSION:
+ rrv = data + sizeof(*hdr);
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+ remote_version_complete(btdev, le16_to_cpu(rrv->handle));
+ break;
+
+ case BT_HCI_CMD_READ_DEFAULT_LINK_POLICY:
+ rdlp.status = BT_HCI_ERR_SUCCESS;
+ rdlp.policy = cpu_to_le16(btdev->default_link_policy);
+ cmd_complete(btdev, opcode, &rdlp, sizeof(rdlp));
+ break;
+
+ case BT_HCI_CMD_WRITE_DEFAULT_LINK_POLICY:
+ wdlp = data + sizeof(*hdr);
+ btdev->default_link_policy = le16_to_cpu(wdlp->policy);
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_SET_EVENT_MASK:
+ sem = data + sizeof(*hdr);
+ memcpy(btdev->event_mask, sem->mask, 8);
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_RESET:
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_SET_EVENT_FILTER:
+ sef = data + sizeof(*hdr);
+ btdev->event_filter = sef->type;
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_STORED_LINK_KEY:
+ rslk.status = BT_HCI_ERR_SUCCESS;
+ rslk.max_num_keys = cpu_to_le16(0);
+ rslk.num_keys = cpu_to_le16(0);
+ cmd_complete(btdev, opcode, &rslk, sizeof(rslk));
+ break;
+
+ case BT_HCI_CMD_WRITE_STORED_LINK_KEY:
+ wslk.status = BT_HCI_ERR_SUCCESS;
+ wslk.num_keys = 0;
+ cmd_complete(btdev, opcode, &wslk, sizeof(wslk));
+ break;
+
+ case BT_HCI_CMD_DELETE_STORED_LINK_KEY:
+ dslk.status = BT_HCI_ERR_SUCCESS;
+ dslk.num_keys = cpu_to_le16(0);
+ cmd_complete(btdev, opcode, &dslk, sizeof(dslk));
+ break;
+
+ case BT_HCI_CMD_WRITE_LOCAL_NAME:
+ wln = data + sizeof(*hdr);
+ memcpy(btdev->name, wln->name, 248);
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_LOCAL_NAME:
+ rln.status = BT_HCI_ERR_SUCCESS;
+ memcpy(rln.name, btdev->name, 248);
+ cmd_complete(btdev, opcode, &rln, sizeof(rln));
+ break;
+
+ case BT_HCI_CMD_READ_CONN_ACCEPT_TIMEOUT:
+ rcat.status = BT_HCI_ERR_SUCCESS;
+ rcat.timeout = cpu_to_le16(btdev->conn_accept_timeout);
+ cmd_complete(btdev, opcode, &rcat, sizeof(rcat));
+ break;
+
+ case BT_HCI_CMD_WRITE_CONN_ACCEPT_TIMEOUT:
+ wcat = data + sizeof(*hdr);
+ btdev->conn_accept_timeout = le16_to_cpu(wcat->timeout);
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_PAGE_TIMEOUT:
+ rpt.status = BT_HCI_ERR_SUCCESS;
+ rpt.timeout = cpu_to_le16(btdev->page_timeout);
+ cmd_complete(btdev, opcode, &rpt, sizeof(rpt));
+ break;
+
+ case BT_HCI_CMD_WRITE_PAGE_TIMEOUT:
+ wpt = data + sizeof(*hdr);
+ btdev->page_timeout = le16_to_cpu(wpt->timeout);
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_SCAN_ENABLE:
+ rse.status = BT_HCI_ERR_SUCCESS;
+ rse.enable = btdev->scan_enable;
+ cmd_complete(btdev, opcode, &rse, sizeof(rse));
+ break;
+
+ case BT_HCI_CMD_WRITE_SCAN_ENABLE:
+ wse = data + sizeof(*hdr);
+ btdev->scan_enable = wse->enable;
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_AUTH_ENABLE:
+ rae.status = BT_HCI_ERR_SUCCESS;
+ rae.enable = btdev->auth_enable;
+ cmd_complete(btdev, opcode, &rae, sizeof(rae));
+ break;
+
+ case BT_HCI_CMD_WRITE_AUTH_ENABLE:
+ wae = data + sizeof(*hdr);
+ btdev->auth_enable = wae->enable;
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_CLASS_OF_DEV:
+ rcod.status = BT_HCI_ERR_SUCCESS;
+ memcpy(rcod.dev_class, btdev->dev_class, 3);
+ cmd_complete(btdev, opcode, &rcod, sizeof(rcod));
+ break;
+
+ case BT_HCI_CMD_WRITE_CLASS_OF_DEV:
+ wcod = data + sizeof(*hdr);
+ memcpy(btdev->dev_class, wcod->dev_class, 3);
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_VOICE_SETTING:
+ rvs.status = BT_HCI_ERR_SUCCESS;
+ rvs.setting = cpu_to_le16(btdev->voice_setting);
+ cmd_complete(btdev, opcode, &rvs, sizeof(rvs));
+ break;
+
+ case BT_HCI_CMD_WRITE_VOICE_SETTING:
+ wvs = data + sizeof(*hdr);
+ btdev->voice_setting = le16_to_cpu(wvs->setting);
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_INQUIRY_MODE:
+ rim.status = BT_HCI_ERR_SUCCESS;
+ rim.mode = btdev->inquiry_mode;
+ cmd_complete(btdev, opcode, &rim, sizeof(rim));
+ break;
+
+ case BT_HCI_CMD_WRITE_INQUIRY_MODE:
+ wim = data + sizeof(*hdr);
+ btdev->inquiry_mode = wim->mode;
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_AFH_ASSESS_MODE:
+ raam.status = BT_HCI_ERR_SUCCESS;
+ raam.mode = btdev->afh_assess_mode;
+ cmd_complete(btdev, opcode, &raam, sizeof(raam));
+ break;
+
+ case BT_HCI_CMD_WRITE_AFH_ASSESS_MODE:
+ waam = data + sizeof(*hdr);
+ btdev->afh_assess_mode = waam->mode;
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_EXT_INQUIRY_RSP:
+ reir.status = BT_HCI_ERR_SUCCESS;
+ reir.fec = btdev->ext_inquiry_fec;
+ memcpy(reir.data, btdev->ext_inquiry_rsp, 240);
+ cmd_complete(btdev, opcode, &reir, sizeof(reir));
+ break;
+
+ case BT_HCI_CMD_WRITE_EXT_INQUIRY_RSP:
+ weir = data + sizeof(*hdr);
+ btdev->ext_inquiry_fec = weir->fec;
+ memcpy(btdev->ext_inquiry_rsp, weir->data, 240);
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE:
+ rspm.status = BT_HCI_ERR_SUCCESS;
+ rspm.mode = btdev->simple_pairing_mode;
+ cmd_complete(btdev, opcode, &rspm, sizeof(rspm));
+ break;
+
+ case BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE:
+ wspm = data + sizeof(*hdr);
+ btdev->simple_pairing_mode = wspm->mode;
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_INQUIRY_RSP_TX_POWER:
+ rirtp.status = BT_HCI_ERR_SUCCESS;
+ rirtp.level = 0;
+ cmd_complete(btdev, opcode, &rirtp, sizeof(rirtp));
+ break;
+
+ case BT_HCI_CMD_READ_LE_HOST_SUPPORTED:
+ rlhs.status = BT_HCI_ERR_SUCCESS;
+ rlhs.supported = btdev->le_supported;
+ rlhs.simultaneous = btdev->le_simultaneous;
+ cmd_complete(btdev, opcode, &rlhs, sizeof(rlhs));
+ break;
+
+ case BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED:
+ wlhs = data + sizeof(*hdr);
+ btdev->le_supported = wlhs->supported;
+ btdev->le_simultaneous = wlhs->simultaneous;
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_READ_LOCAL_VERSION:
+ rlv.status = BT_HCI_ERR_SUCCESS;
+ rlv.hci_ver = btdev->version;
+ rlv.hci_rev = cpu_to_le16(btdev->revision);
+ rlv.lmp_ver = btdev->version;
+ rlv.manufacturer = cpu_to_le16(btdev->manufacturer);
+ rlv.lmp_subver = cpu_to_le16(btdev->revision);
+ cmd_complete(btdev, opcode, &rlv, sizeof(rlv));
+ break;
+
+ case BT_HCI_CMD_READ_LOCAL_COMMANDS:
+ rlc.status = BT_HCI_ERR_SUCCESS;
+ memcpy(rlc.commands, btdev->commands, 64);
+ cmd_complete(btdev, opcode, &rlc, sizeof(rlc));
+ break;
+
+ case BT_HCI_CMD_READ_LOCAL_FEATURES:
+ rlf.status = BT_HCI_ERR_SUCCESS;
+ memcpy(rlf.features, btdev->features, 8);
+ cmd_complete(btdev, opcode, &rlf, sizeof(rlf));
+ break;
+
+ case BT_HCI_CMD_READ_LOCAL_EXT_FEATURES:
+ page = ((const uint8_t *) data)[sizeof(*hdr)];
+ switch (page) {
+ case 0x00:
+ rlef.status = BT_HCI_ERR_SUCCESS;
+ rlef.page = 0x00;
+ rlef.max_page = 0x01;
+ memcpy(rlef.features, btdev->features, 8);
+ break;
+ case 0x01:
+ rlef.status = BT_HCI_ERR_SUCCESS;
+ rlef.page = 0x01;
+ rlef.max_page = 0x01;
+ memset(rlef.features, 0, 8);
+ if (btdev->simple_pairing_mode)
+ rlef.features[0] |= 0x01;
+ if (btdev->le_supported)
+ rlef.features[0] |= 0x02;
+ if (btdev->le_simultaneous)
+ rlef.features[0] |= 0x04;
+ break;
+ default:
+ rlef.status = BT_HCI_ERR_INVALID_PARAMETERS;
+ rlef.page = page;
+ rlef.max_page = 0x01;
+ memset(rlef.features, 0, 8);
+ break;
+ }
+ cmd_complete(btdev, opcode, &rlef, sizeof(rlef));
+ break;
+
+ case BT_HCI_CMD_READ_BUFFER_SIZE:
+ rbs.status = BT_HCI_ERR_SUCCESS;
+ rbs.acl_mtu = cpu_to_le16(btdev->acl_mtu);
+ rbs.sco_mtu = 0;
+ rbs.acl_max_pkt = cpu_to_le16(btdev->acl_max_pkt);
+ rbs.sco_max_pkt = cpu_to_le16(0);
+ cmd_complete(btdev, opcode, &rbs, sizeof(rbs));
+ break;
+
+ case BT_HCI_CMD_READ_COUNTRY_CODE:
+ rcc.status = BT_HCI_ERR_SUCCESS;
+ rcc.code = btdev->country_code;
+ cmd_complete(btdev, opcode, &rcc, sizeof(rcc));
+ break;
+
+ case BT_HCI_CMD_READ_BD_ADDR:
+ rba.status = BT_HCI_ERR_SUCCESS;
+ memcpy(rba.bdaddr, btdev->bdaddr, 6);
+ cmd_complete(btdev, opcode, &rba, sizeof(rba));
+ break;
+
+ case BT_HCI_CMD_READ_DATA_BLOCK_SIZE:
+ rdbs.status = BT_HCI_ERR_SUCCESS;
+ rdbs.max_acl_len = cpu_to_le16(btdev->acl_mtu);
+ rdbs.block_len = cpu_to_le16(btdev->acl_mtu);
+ rdbs.num_blocks = cpu_to_le16(btdev->acl_max_pkt);
+ cmd_complete(btdev, opcode, &rdbs, sizeof(rdbs));
+ break;
+
+ case BT_HCI_CMD_LE_SET_EVENT_MASK:
+ lsem = data + sizeof(*hdr);
+ memcpy(btdev->le_event_mask, lsem->mask, 8);
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_LE_READ_BUFFER_SIZE:
+ lrbs.status = BT_HCI_ERR_SUCCESS;
+ lrbs.le_mtu = cpu_to_le16(btdev->acl_mtu);
+ lrbs.le_max_pkt = btdev->acl_max_pkt;
+ cmd_complete(btdev, opcode, &lrbs, sizeof(lrbs));
+ break;
+
+ case BT_HCI_CMD_LE_READ_LOCAL_FEATURES:
+ lrlf.status = BT_HCI_ERR_SUCCESS;
+ memcpy(lrlf.features, btdev->le_features, 8);
+ cmd_complete(btdev, opcode, &lrlf, sizeof(lrlf));
+ break;
+
+ case BT_HCI_CMD_LE_SET_SCAN_PARAMETERS:
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_LE_SET_SCAN_ENABLE:
+ status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &status, sizeof(status));
+ break;
+
+ case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
+ lrss.status = BT_HCI_ERR_SUCCESS;
+ memcpy(lrss.states, btdev->le_states, 8);
+ cmd_complete(btdev, opcode, &lrss, sizeof(lrss));
+ break;
+
+ default:
+ printf("Unsupported command 0x%4.4x\n", opcode);
+ hexdump(data, len);
+ cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, opcode);
+ break;
+ }
+}
+
+void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
+{
+ uint8_t pkt_type;
+
+ if (!btdev)
+ return;
+
+ if (len < 1)
+ return;
+
+ pkt_type = ((const uint8_t *) data)[0];
+
+ switch (pkt_type) {
+ case BT_H4_CMD_PKT:
+ process_cmd(btdev, data + 1, len - 1);
+ break;
+ case BT_H4_ACL_PKT:
+ if (btdev->conn)
+ send_packet(btdev->conn, data, len);
+ num_completed_packets(btdev);
+ break;
+ default:
+ printf("Unsupported packet 0x%2.2x\n", pkt_type);
+ break;
+ }
+}
diff --git a/tools/emulator/btdev.h b/tools/emulator/btdev.h
new file mode 100644
index 0000000..7b211a2
--- /dev/null
+++ b/tools/emulator/btdev.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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
+ *
+ */
+
+#include <stdint.h>
+
+typedef void (*btdev_send_func) (const void *data, uint16_t len,
+ void *user_data);
+
+struct btdev;
+
+struct btdev *btdev_create(uint16_t id);
+void btdev_destroy(struct btdev *btdev);
+
+void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
+ void *user_data);
+
+void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len);
diff --git a/tools/emulator/main.c b/tools/emulator/main.c
new file mode 100644
index 0000000..125460d
--- /dev/null
+++ b/tools/emulator/main.c
@@ -0,0 +1,73 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 <stdio.h>
+
+#include "mainloop.h"
+#include "server.h"
+#include "vhci.h"
+
+static void signal_callback(int signum, void *user_data)
+{
+ switch (signum) {
+ case SIGINT:
+ case SIGTERM:
+ mainloop_quit();
+ break;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct vhci *vhci;
+ struct server *server;
+ sigset_t mask;
+
+ mainloop_init();
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+
+ mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+
+ vhci = vhci_open(VHCI_TYPE_BREDR, 0x23);
+ if (!vhci) {
+ fprintf(stderr, "Failed to open Virtual HCI device\n");
+ return 1;
+ }
+
+ server = server_open_unix("/tmp/bt-server-bredr", 0x42);
+ if (!server) {
+ fprintf(stderr, "Failed to open server channel\n");
+ vhci_close(vhci);
+ return 1;
+ }
+
+ return mainloop_run();
+}
diff --git a/tools/emulator/server.c b/tools/emulator/server.c
new file mode 100644
index 0000000..1ff9904
--- /dev/null
+++ b/tools/emulator/server.c
@@ -0,0 +1,288 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+#include "mainloop.h"
+#include "btdev.h"
+#include "server.h"
+
+struct server {
+ uint16_t id;
+ int fd;
+};
+
+struct client {
+ int fd;
+ struct btdev *btdev;
+ uint8_t *pkt_data;
+ uint8_t pkt_type;
+ uint16_t pkt_expect;
+ uint16_t pkt_len;
+ uint16_t pkt_offset;
+};
+
+static void server_destroy(void *user_data)
+{
+ struct server *server = user_data;
+
+ close(server->fd);
+
+ free(server);
+}
+
+static void client_destroy(void *user_data)
+{
+ struct client *client = user_data;
+
+ btdev_destroy(client->btdev);
+
+ close(client->fd);
+
+ free(client);
+}
+
+static void client_write_callback(const void *data, uint16_t len,
+ void *user_data)
+{
+ struct client *client = user_data;
+ ssize_t written;
+
+ written = send(client->fd, data, len, MSG_DONTWAIT);
+ if (written < 0)
+ return;
+}
+
+static void client_read_callback(int fd, uint32_t events, void *user_data)
+{
+ struct client *client = user_data;
+ static uint8_t buf[4096];
+ uint8_t *ptr = buf;
+ ssize_t len;
+ uint16_t count;
+
+ if (events & (EPOLLERR | EPOLLHUP))
+ return;
+
+again:
+ len = recv(fd, buf + client->pkt_offset,
+ sizeof(buf) - client->pkt_offset, MSG_DONTWAIT);
+ if (len < 0) {
+ if (errno == EAGAIN)
+ goto again;
+ return;
+ }
+
+ count = client->pkt_offset + len;
+
+ while (count > 0) {
+ hci_command_hdr *cmd_hdr;
+
+ if (!client->pkt_data) {
+ client->pkt_type = ptr[0];
+
+ switch (client->pkt_type) {
+ case HCI_COMMAND_PKT:
+ if (count < HCI_COMMAND_HDR_SIZE + 1) {
+ client->pkt_offset += len;
+ return;
+ }
+ cmd_hdr = (hci_command_hdr *) (ptr + 1);
+ client->pkt_expect = HCI_COMMAND_HDR_SIZE +
+ cmd_hdr->plen + 1;
+ client->pkt_data = malloc(client->pkt_expect);
+ client->pkt_len = 0;
+ break;
+ default:
+ printf("packet error\n");
+ return;
+ }
+
+ client->pkt_offset = 0;
+ }
+
+ if (count >= client->pkt_expect) {
+ memcpy(client->pkt_data + client->pkt_len,
+ ptr, client->pkt_expect);
+ ptr += client->pkt_expect;
+ count -= client->pkt_expect;
+
+ btdev_receive_h4(client->btdev, client->pkt_data,
+ client->pkt_len + client->pkt_expect);
+
+ free(client->pkt_data);
+ client->pkt_data = NULL;
+ } else {
+ memcpy(client->pkt_data + client->pkt_len, ptr, count);
+ client->pkt_len += count;
+ client->pkt_expect -= count;
+ count = 0;
+ }
+ }
+}
+
+static int accept_client(int fd)
+{
+ struct sockaddr_un addr;
+ socklen_t len;
+ int nfd;
+
+ memset(&addr, 0, sizeof(addr));
+ len = sizeof(addr);
+
+ if (getsockname(fd, (struct sockaddr *) &addr, &len) < 0) {
+ perror("Failed to get socket name");
+ return -1;
+ }
+
+ printf("Request for %s\n", addr.sun_path);
+
+ nfd = accept(fd, (struct sockaddr *) &addr, &len);
+ if (nfd < 0) {
+ perror("Failed to accept client socket");
+ return -1;
+ }
+
+ return nfd;
+}
+
+static void server_accept_callback(int fd, uint32_t events, void *user_data)
+{
+ struct server *server = user_data;
+ struct client *client;
+
+ if (events & (EPOLLERR | EPOLLHUP))
+ return;
+
+ client = malloc(sizeof(*client));
+ if (!client)
+ return;
+
+ memset(client, 0, sizeof(*client));
+
+ client->fd = accept_client(server->fd);
+ if (client->fd < 0) {
+ free(client);
+ return;
+ }
+
+ client->btdev = btdev_create(server->id);
+ if (!client->btdev) {
+ close(client->fd);
+ free(client);
+ return;
+ }
+
+ btdev_set_send_handler(client->btdev, client_write_callback, client);
+
+ if (mainloop_add_fd(client->fd, EPOLLIN, client_read_callback,
+ client, client_destroy) < 0) {
+ btdev_destroy(client->btdev);
+ close(client->fd);
+ free(client);
+ }
+}
+
+static int open_server(const char *path)
+{
+ struct sockaddr_un addr;
+ int fd;
+
+ unlink(path);
+
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ perror("Failed to open server socket");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, path);
+
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("Failed to bind server socket");
+ close(fd);
+ return -1;
+ }
+
+ if (listen(fd, 5) < 0) {
+ perror("Failed to listen server socket");
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+struct server *server_open_unix(const char *path, uint16_t id)
+{
+ struct server *server;
+
+ server = malloc(sizeof(*server));
+ if (!server)
+ return NULL;
+
+ memset(server, 0, sizeof(*server));
+ server->id = id;
+
+ server->fd = open_server(path);
+ if (server->fd < 0) {
+ free(server);
+ return NULL;
+ }
+
+ if (mainloop_add_fd(server->fd, EPOLLIN, server_accept_callback,
+ server, server_destroy) < 0) {
+ close(server->fd);
+ free(server);
+ return NULL;
+ }
+
+ return server;
+}
+
+void server_close(struct server *server)
+{
+ if (!server)
+ return;
+
+ mainloop_remove_fd(server->fd);
+}
diff --git a/tools/emulator/server.h b/tools/emulator/server.h
new file mode 100644
index 0000000..836db5f
--- /dev/null
+++ b/tools/emulator/server.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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
+ *
+ */
+
+#include <stdint.h>
+
+struct server;
+
+struct server *server_open_unix(const char *path, uint16_t id);
+void server_close(struct server *server);
diff --git a/tools/emulator/vhci.c b/tools/emulator/vhci.c
new file mode 100644
index 0000000..940e562
--- /dev/null
+++ b/tools/emulator/vhci.c
@@ -0,0 +1,133 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mainloop.h"
+#include "btdev.h"
+#include "vhci.h"
+
+struct vhci {
+ enum vhci_type type;
+ int fd;
+ struct btdev *btdev;
+};
+
+static void vhci_destroy(void *user_data)
+{
+ struct vhci *vhci = user_data;
+
+ btdev_destroy(vhci->btdev);
+
+ close(vhci->fd);
+
+ free(vhci);
+}
+
+static void vhci_write_callback(const void *data, uint16_t len, void *user_data)
+{
+ struct vhci *vhci = user_data;
+ ssize_t written;
+
+ written = write(vhci->fd, data, len);
+ if (written < 0)
+ return;
+}
+
+static void vhci_read_callback(int fd, uint32_t events, void *user_data)
+{
+ struct vhci *vhci = user_data;
+ unsigned char buf[4096];
+ ssize_t len;
+
+ if (events & (EPOLLERR | EPOLLHUP))
+ return;
+
+ len = read(vhci->fd, buf, sizeof(buf));
+ if (len < 0)
+ return;
+
+ btdev_receive_h4(vhci->btdev, buf, len);
+}
+
+struct vhci *vhci_open(enum vhci_type type, uint16_t id)
+{
+ struct vhci *vhci;
+
+ switch (type) {
+ case VHCI_TYPE_BREDR:
+ break;
+ case VHCI_TYPE_AMP:
+ return NULL;
+ }
+
+ vhci = malloc(sizeof(*vhci));
+ if (!vhci)
+ return NULL;
+
+ memset(vhci, 0, sizeof(*vhci));
+ vhci->type = type;
+
+ vhci->fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
+ if (vhci->fd < 0) {
+ free(vhci);
+ return NULL;
+ }
+
+ vhci->btdev = btdev_create(id);
+ if (!vhci->btdev) {
+ close(vhci->fd);
+ free(vhci);
+ return NULL;
+ }
+
+ btdev_set_send_handler(vhci->btdev, vhci_write_callback, vhci);
+
+ if (mainloop_add_fd(vhci->fd, EPOLLIN, vhci_read_callback,
+ vhci, vhci_destroy) < 0) {
+ btdev_destroy(vhci->btdev);
+ close(vhci->fd);
+ free(vhci);
+ return NULL;
+ }
+
+ return vhci;
+}
+
+void vhci_close(struct vhci *vhci)
+{
+ if (!vhci)
+ return;
+
+ mainloop_remove_fd(vhci->fd);
+}
diff --git a/tools/emulator/vhci.h b/tools/emulator/vhci.h
new file mode 100644
index 0000000..4abb183
--- /dev/null
+++ b/tools/emulator/vhci.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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
+ *
+ */
+
+#include <stdint.h>
+
+enum vhci_type {
+ VHCI_TYPE_BREDR = 0,
+ VHCI_TYPE_AMP = 1,
+};
+
+struct vhci;
+
+struct vhci *vhci_open(enum vhci_type type, uint16_t id);
+void vhci_close(struct vhci *vhci);
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 16/21] btmgmt: move to tools folder
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (13 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 15/21] emulator: move it to the tools folder Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 17/21] alert: move alert to profiles dir Gustavo Padovan
` (4 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
.gitignore | 2 +-
Makefile.tools | 8 +-
mgmt/main.c | 1933 -----------------------------------------------------
tools/mgmt/main.c | 1933 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 1938 insertions(+), 1938 deletions(-)
delete mode 100644 mgmt/main.c
create mode 100644 tools/mgmt/main.c
diff --git a/.gitignore b/.gitignore
index 7bbefc9..fa1a215 100644
--- a/.gitignore
+++ b/.gitignore
@@ -84,7 +84,7 @@ compat/dund
compat/hidd
compat/pand
unit/test-eir
-mgmt/btmgmt
+tools/mgmt/btmgmt
monitor/btmon
tools/emulator/btvirt
diff --git a/Makefile.tools b/Makefile.tools
index f7c6f9f..36b7178 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -50,10 +50,10 @@ tools_ppporc_LDADD = lib/libbluetooth-private.la
tools_hcieventmask_LDADD = lib/libbluetooth-private.la
-noinst_PROGRAMS += mgmt/btmgmt monitor/btmon tools/emulator/btvirt
+noinst_PROGRAMS += tools/mgmt/btmgmt monitor/btmon tools/emulator/btvirt
-mgmt_btmgmt_SOURCES = mgmt/main.c src/glib-helper.c
-mgmt_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
+tools_mgmt_btmgmt_SOURCES = tools/mgmt/main.c src/glib-helper.c
+tools_mgmt_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
monitor/mainloop.h monitor/mainloop.c \
@@ -63,7 +63,7 @@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
monitor/packet.h monitor/packet.c
monitor_btmon_LDADD = lib/libbluetooth-private.la
-emulator_btvirt_SOURCES = tools/emulator/main.c monitor/bt.h \
+tools_emulator_btvirt_SOURCES = tools/emulator/main.c monitor/bt.h \
monitor/mainloop.h monitor/mainloop.c \
tools/emulator/server.h tools/emulator/server.c \
tools/emulator/vhci.h tools/emulator/vhci.c \
diff --git a/mgmt/main.c b/mgmt/main.c
deleted file mode 100644
index b2d6c3c..0000000
--- a/mgmt/main.c
+++ /dev/null
@@ -1,1933 +0,0 @@
-/*
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 Intel Corporation. All rights reserved.
- *
- * 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 <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <poll.h>
-#include <getopt.h>
-#include <stdbool.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/mgmt.h>
-
-#include <glib.h>
-#include "glib-helper.h"
-
-static bool monitor = false;
-static bool discovery = false;
-static bool resolve_names = true;
-
-typedef void (*cmd_cb)(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data);
-
-static struct pending_cmd {
- uint16_t op;
- uint16_t id;
- cmd_cb cb;
- void *user_data;
- struct pending_cmd *next;
-} *pending = NULL;
-
-static int mgmt_send_cmd(int mgmt_sk, uint16_t op, uint16_t id, void *data,
- size_t len, cmd_cb func, void *user_data)
-{
- char buf[1024];
- struct pending_cmd *cmd;
- struct mgmt_hdr *hdr = (void *) buf;
-
- if (len + MGMT_HDR_SIZE > sizeof(buf))
- return -EINVAL;
-
- cmd = calloc(1, sizeof(struct pending_cmd));
- if (cmd == NULL)
- return -errno;
-
- cmd->op = op;
- cmd->id = id;
- cmd->cb = func;
- cmd->user_data = user_data;
-
- memset(buf, 0, sizeof(buf));
- hdr->opcode = htobs(op);
- hdr->index = htobs(id);
- hdr->len = htobs(len);
- memcpy(buf + MGMT_HDR_SIZE, data, len);
-
- if (write(mgmt_sk, buf, MGMT_HDR_SIZE + len) < 0) {
- fprintf(stderr, "Unable to write to socket: %s\n",
- strerror(errno));
- free(cmd);
- return -1;
- }
-
- cmd->next = pending;
- pending = cmd;
-
- return 0;
-}
-
-static int mgmt_open(void)
-{
- struct sockaddr_hci addr;
- int sk;
-
- sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
- if (sk < 0) {
- fprintf(stderr, "socket: %s\n", strerror(errno));
- return sk;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.hci_family = AF_BLUETOOTH;
- addr.hci_dev = HCI_DEV_NONE;
- addr.hci_channel = HCI_CHANNEL_CONTROL;
-
- if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- fprintf(stderr, "bind: %s\n", strerror(errno));
- close(sk);
- return -1;
- }
-
- return sk;
-}
-
-static void mgmt_check_pending(int mgmt_sk, uint16_t op, uint16_t index,
- uint16_t status, void *data, uint16_t len)
-{
- struct pending_cmd *c, *prev;
-
- for (c = pending, prev = NULL; c != NULL; prev = c, c = c->next) {
- if (c->op != op)
- continue;
- if (c->id != index)
- continue;
-
- if (c == pending)
- pending = c->next;
- else
- prev->next = c->next;
-
- c->cb(mgmt_sk, op, index, status, data, len, c->user_data);
-
- free(c);
- break;
- }
-}
-
-static int mgmt_cmd_complete(int mgmt_sk, uint16_t index,
- struct mgmt_ev_cmd_complete *ev, uint16_t len)
-{
- uint16_t op;
-
- if (len < sizeof(*ev)) {
- fprintf(stderr, "Too short (%u bytes) cmd complete event\n",
- len);
- return -EINVAL;
- }
-
- op = bt_get_le16(&ev->opcode);
-
- len -= sizeof(*ev);
-
- if (monitor)
- printf("%s complete, opcode 0x%04x len %u\n", mgmt_opstr(op),
- op, len);
-
- mgmt_check_pending(mgmt_sk, op, index, ev->status, ev->data, len);
-
- return 0;
-}
-
-static int mgmt_cmd_status(int mgmt_sk, uint16_t index,
- struct mgmt_ev_cmd_status *ev, uint16_t len)
-{
- uint16_t opcode;
-
- if (len < sizeof(*ev)) {
- fprintf(stderr, "Too short (%u bytes) cmd status event\n",
- len);
- return -EINVAL;
- }
-
- opcode = bt_get_le16(&ev->opcode);
-
- if (monitor)
- printf("cmd status, opcode 0x%04x status 0x%02x (%s)\n",
- opcode, ev->status, mgmt_errstr(ev->status));
-
- if (ev->status != 0)
- mgmt_check_pending(mgmt_sk, opcode, index, ev->status,
- NULL, 0);
-
- return 0;
-}
-
-static int mgmt_controller_error(uint16_t index,
- struct mgmt_ev_controller_error *ev,
- uint16_t len)
-{
- if (len < sizeof(*ev)) {
- fprintf(stderr,
- "Too short (%u bytes) controller error event\n", len);
- return -EINVAL;
- }
-
- if (monitor)
- printf("hci%u error 0x%02x\n", index, ev->error_code);
-
- return 0;
-}
-
-static int mgmt_index_added(int mgmt_sk, uint16_t index)
-{
- if (monitor)
- printf("hci%u added\n", index);
- return 0;
-}
-
-static int mgmt_index_removed(int mgmt_sk, uint16_t index)
-{
- if (monitor)
- printf("hci%u removed\n", index);
- return 0;
-}
-
-static const char *settings_str[] = {
- "powered",
- "connectable",
- "fast-connectable",
- "discoverable",
- "pairable",
- "link-security",
- "ssp",
- "br/edr",
- "hs",
- "le" ,
-};
-
-static void print_settings(uint32_t settings)
-{
- unsigned i;
-
- for (i = 0; i < NELEM(settings_str); i++) {
- if ((settings & (1 << i)) != 0)
- printf("%s ", settings_str[i]);
- }
-}
-
-static int mgmt_new_settings(int mgmt_sk, uint16_t index,
- uint32_t *ev, uint16_t len)
-{
- if (len < sizeof(*ev)) {
- fprintf(stderr, "Too short new_settings event (%u)\n", len);
- return -EINVAL;
- }
-
- if (monitor) {
- printf("hci%u new_settings: ", index);
- print_settings(bt_get_le32(ev));
- printf("\n");
- }
-
- return 0;
-}
-
-static int mgmt_discovering(int mgmt_sk, uint16_t index,
- struct mgmt_ev_discovering *ev, uint16_t len)
-{
- if (len < sizeof(*ev)) {
- fprintf(stderr, "Too short (%u bytes) discovering event\n",
- len);
- return -EINVAL;
- }
-
- if (ev->discovering == 0 && discovery)
- exit(EXIT_SUCCESS);
-
- if (monitor)
- printf("hci%u type %u discovering %s\n", index,
- ev->type, ev->discovering ? "on" : "off");
-
- return 0;
-}
-
-static int mgmt_new_link_key(int mgmt_sk, uint16_t index,
- struct mgmt_ev_new_link_key *ev, uint16_t len)
-{
-
- if (len != sizeof(*ev)) {
- fprintf(stderr, "Invalid new_link_key length (%u bytes)\n",
- len);
- return -EINVAL;
- }
-
- if (monitor) {
- char addr[18];
- ba2str(&ev->key.addr.bdaddr, addr);
- printf("hci%u new_link_key %s type 0x%02x pin_len %d "
- "store_hint %u\n", index, addr, ev->key.type,
- ev->key.pin_len, ev->store_hint);
- }
-
- return 0;
-}
-
-static const char *typestr(uint8_t type)
-{
- const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
-
- if (type <= BDADDR_LE_RANDOM)
- return str[type];
-
- return "(unknown)";
-}
-
-static int mgmt_connected(int mgmt_sk, uint16_t index,
- struct mgmt_ev_device_connected *ev,
- uint16_t len)
-{
- uint16_t eir_len;
-
- if (len < sizeof(*ev)) {
- fprintf(stderr,
- "Invalid connected event length (%u bytes)\n", len);
- return -EINVAL;
- }
-
- eir_len = bt_get_le16(&ev->eir_len);
- if (len != sizeof(*ev) + eir_len) {
- fprintf(stderr, "Invalid connected event length "
- "(%u bytes, eir_len %u bytes)\n", len, eir_len);
- return -EINVAL;
- }
-
- if (monitor) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s type %s connected eir_len %u\n", index, addr,
- typestr(ev->addr.type), eir_len);
- }
-
- return 0;
-}
-
-static int mgmt_disconnected(int mgmt_sk, uint16_t index,
- struct mgmt_addr_info *ev, uint16_t len)
-{
- if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid disconnected event length (%u bytes)\n", len);
- return -EINVAL;
- }
-
- if (monitor) {
- char addr[18];
- ba2str(&ev->bdaddr, addr);
- printf("hci%u %s type %s disconnected\n", index, addr,
- typestr(ev->type));
- }
-
- return 0;
-}
-
-static int mgmt_conn_failed(int mgmt_sk, uint16_t index,
- struct mgmt_ev_connect_failed *ev,
- uint16_t len)
-{
- if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid connect_failed event length (%u bytes)\n", len);
- return -EINVAL;
- }
-
- if (monitor) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s type %s connect failed (status 0x%02x, %s)\n",
- index, addr, typestr(ev->addr.type), ev->status,
- mgmt_errstr(ev->status));
- }
-
- return 0;
-}
-
-static int mgmt_auth_failed(int mgmt_sk, uint16_t index,
- struct mgmt_ev_auth_failed *ev,
- uint16_t len)
-{
- if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid auth_failed event length (%u bytes)\n", len);
- return -EINVAL;
- }
-
- if (monitor) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s auth failed with status 0x%02x (%s)\n",
- index, addr, ev->status, mgmt_errstr(ev->status));
- }
-
- return 0;
-}
-
-static int mgmt_name_changed(int mgmt_sk, uint16_t index,
- struct mgmt_ev_local_name_changed *ev,
- uint16_t len)
-{
- if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid local_name_changed length (%u bytes)\n", len);
- return -EINVAL;
- }
-
- if (monitor)
- printf("hci%u name changed: %s\n", index, ev->name);
-
- return 0;
-}
-
-static void confirm_name_rsp(int mgmt_sk, uint16_t op, uint16_t id,
- uint8_t status, void *rsp, uint16_t len,
- void *user_data)
-{
- struct mgmt_rp_confirm_name *rp = rsp;
- char addr[18];
-
- if (len == 0 && status != 0) {
- fprintf(stderr,
- "hci%u confirm_name failed with status 0x%02x (%s)\n",
- id, status, mgmt_errstr(status));
- return;
- }
-
- if (len != sizeof(*rp)) {
- fprintf(stderr,
- "hci%u confirm_name rsp length %u instead of %zu\n",
- id, len, sizeof(*rp));
- return;
- }
-
- ba2str(&rp->addr.bdaddr, addr);
-
- if (status != 0)
- fprintf(stderr,
- "hci%u confirm_name for %s failed: 0x%02x (%s)\n",
- id, addr, status, mgmt_errstr(status));
- else
- printf("hci%u confirm_name succeeded for %s\n", id, addr);
-}
-
-static int mgmt_device_found(int mgmt_sk, uint16_t index,
- struct mgmt_ev_device_found *ev, uint16_t len)
-{
- uint32_t flags;
- uint16_t eir_len;
-
- if (len < sizeof(*ev)) {
- fprintf(stderr,
- "Too short device_found length (%u bytes)\n", len);
- return -EINVAL;
- }
-
- flags = btohs(ev->flags);
-
- eir_len = bt_get_le16(&ev->eir_len);
- if (len != sizeof(*ev) + eir_len) {
- fprintf(stderr, "dev_found: expected %zu bytes, got %u bytes",
- sizeof(*ev) + eir_len, len);
- return -EINVAL;
- }
-
- if (monitor || discovery) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u dev_found: %s type %s rssi %d "
- "flags 0x%04x eir_len %u\n", index, addr,
- typestr(ev->addr.type), ev->rssi, flags, eir_len);
- }
-
- if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) {
- struct mgmt_cp_confirm_name cp;
-
- memset(&cp, 0, sizeof(cp));
- memcpy(&cp.addr, &ev->addr, sizeof(cp.addr));
- if (resolve_names)
- cp.name_known = 0;
- else
- cp.name_known = 1;
-
- mgmt_send_cmd(mgmt_sk, MGMT_OP_CONFIRM_NAME, index,
- &cp, sizeof(cp), confirm_name_rsp,
- NULL);
- }
-
- return 0;
-}
-
-static void pin_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- if (status != 0) {
- fprintf(stderr,
- "hci%u PIN Code reply failed with status 0x%02x (%s)",
- id, status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- printf("hci%u PIN Reply successful\n", id);
-}
-
-static int mgmt_pin_reply(int mgmt_sk, uint16_t index,
- struct mgmt_addr_info *addr,
- const char *pin, size_t len)
-{
- struct mgmt_cp_pin_code_reply cp;
-
- memset(&cp, 0, sizeof(cp));
- memcpy(&cp.addr, addr, sizeof(cp.addr));
- cp.pin_len = len;
- memcpy(cp.pin_code, pin, len);
-
- return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_REPLY, index,
- &cp, sizeof(cp), pin_rsp, NULL);
-}
-
-static void pin_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- if (status != 0) {
- fprintf(stderr,
- "hci%u PIN Neg reply failed with status 0x%02x (%s)",
- id, status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- printf("hci%u PIN Negative Reply successful\n", id);
-}
-
-static int mgmt_pin_neg_reply(int mgmt_sk, uint16_t index,
- struct mgmt_addr_info *addr)
-{
- struct mgmt_cp_pin_code_neg_reply cp;
-
- memset(&cp, 0, sizeof(cp));
- memcpy(&cp.addr, addr, sizeof(cp.addr));
-
- return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
- &cp, sizeof(cp), pin_neg_rsp, NULL);
-}
-
-static int mgmt_request_pin(int mgmt_sk, uint16_t index,
- struct mgmt_ev_pin_code_request *ev,
- uint16_t len)
-{
- char pin[18];
- size_t pin_len;
-
- if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid pin_code request length (%u bytes)\n", len);
- return -EINVAL;
- }
-
- if (monitor) {
- char addr[18];
- ba2str(&ev->addr.bdaddr, addr);
- printf("hci%u %s request PIN\n", index, addr);
- }
-
- printf("PIN Request (press enter to reject) >> ");
- fflush(stdout);
-
- memset(pin, 0, sizeof(pin));
-
- if (fgets(pin, sizeof(pin), stdin) == NULL || pin[0] == '\n')
- return mgmt_pin_neg_reply(mgmt_sk, index, &ev->addr);
-
- pin_len = strlen(pin);
- if (pin[pin_len - 1] == '\n') {
- pin[pin_len - 1] = '\0';
- pin_len--;
- }
-
- return mgmt_pin_reply(mgmt_sk, index, &ev->addr, pin, pin_len);
-}
-
-static void confirm_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- if (status != 0) {
- fprintf(stderr,
- "hci%u User Confirm reply failed. status 0x%02x (%s)",
- id, status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- printf("hci%u User Confirm Reply successful\n", id);
-}
-
-static int mgmt_confirm_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr)
-{
- struct mgmt_cp_user_confirm_reply cp;
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.addr.bdaddr, bdaddr);
-
- return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_REPLY, index,
- &cp, sizeof(cp), confirm_rsp, NULL);
-}
-
-static void confirm_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id,
- uint8_t status, void *rsp, uint16_t len,
- void *user_data)
-{
- if (status != 0) {
- fprintf(stderr,
- "hci%u Confirm Neg reply failed. status 0x%02x (%s)",
- id, status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- printf("hci%u User Confirm Negative Reply successful\n", id);
-}
-
-static int mgmt_confirm_neg_reply(int mgmt_sk, uint16_t index,
- bdaddr_t *bdaddr)
-{
- struct mgmt_cp_user_confirm_reply cp;
-
- memset(&cp, 0, sizeof(cp));
- bacpy(&cp.addr.bdaddr, bdaddr);
-
- return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_NEG_REPLY, index,
- &cp, sizeof(cp), confirm_neg_rsp, NULL);
-}
-
-
-static int mgmt_user_confirm(int mgmt_sk, uint16_t index,
- struct mgmt_ev_user_confirm_request *ev,
- uint16_t len)
-{
- char rsp[5];
- size_t rsp_len;
- uint32_t val;
- char addr[18];
-
- if (len != sizeof(*ev)) {
- fprintf(stderr,
- "Invalid user_confirm request length (%u)\n", len);
- return -EINVAL;
- }
-
- ba2str(&ev->addr.bdaddr, addr);
- val = bt_get_le32(&ev->value);
-
- if (monitor)
- printf("hci%u %s User Confirm %06u hint %u\n", index, addr,
- val, ev->confirm_hint);
-
- if (ev->confirm_hint)
- printf("Accept pairing with %s (yes/no) >> ", addr);
- else
- printf("Confirm value %06u for %s (yes/no) >> ", val, addr);
-
- fflush(stdout);
-
- memset(rsp, 0, sizeof(rsp));
-
- if (fgets(rsp, sizeof(rsp), stdin) == NULL || rsp[0] == '\n')
- return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr);
-
- rsp_len = strlen(rsp);
- if (rsp[rsp_len - 1] == '\n') {
- rsp[rsp_len - 1] = '\0';
- rsp_len--;
- }
-
- if (rsp[0] == 'y' || rsp[0] == 'Y')
- return mgmt_confirm_reply(mgmt_sk, index, &ev->addr.bdaddr);
- else
- return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr);
-}
-
-static int mgmt_handle_event(int mgmt_sk, uint16_t ev, uint16_t index,
- void *data, uint16_t len)
-{
- if (monitor)
- printf("event: %s\n", mgmt_evstr(ev));
-
- switch (ev) {
- case MGMT_EV_CMD_COMPLETE:
- return mgmt_cmd_complete(mgmt_sk, index, data, len);
- case MGMT_EV_CMD_STATUS:
- return mgmt_cmd_status(mgmt_sk, index, data, len);
- case MGMT_EV_CONTROLLER_ERROR:
- return mgmt_controller_error(index, data, len);
- case MGMT_EV_INDEX_ADDED:
- return mgmt_index_added(mgmt_sk, index);
- case MGMT_EV_INDEX_REMOVED:
- return mgmt_index_removed(mgmt_sk, index);
- case MGMT_EV_NEW_SETTINGS:
- return mgmt_new_settings(mgmt_sk, index, data, len);
- case MGMT_EV_DISCOVERING:
- return mgmt_discovering(mgmt_sk, index, data, len);
- case MGMT_EV_NEW_LINK_KEY:
- return mgmt_new_link_key(mgmt_sk, index, data, len);
- case MGMT_EV_DEVICE_CONNECTED:
- return mgmt_connected(mgmt_sk, index, data, len);
- case MGMT_EV_DEVICE_DISCONNECTED:
- return mgmt_disconnected(mgmt_sk, index, data, len);
- case MGMT_EV_CONNECT_FAILED:
- return mgmt_conn_failed(mgmt_sk, index, data, len);
- case MGMT_EV_AUTH_FAILED:
- return mgmt_auth_failed(mgmt_sk, index, data, len);
- case MGMT_EV_LOCAL_NAME_CHANGED:
- return mgmt_name_changed(mgmt_sk, index, data, len);
- case MGMT_EV_DEVICE_FOUND:
- return mgmt_device_found(mgmt_sk, index, data, len);
- case MGMT_EV_PIN_CODE_REQUEST:
- return mgmt_request_pin(mgmt_sk, index, data, len);
- case MGMT_EV_USER_CONFIRM_REQUEST:
- return mgmt_user_confirm(mgmt_sk, index, data, len);
- default:
- if (monitor)
- printf("Unhandled event 0x%04x (%s)\n", ev, mgmt_evstr(ev));
- return 0;
- }
-}
-
-static int mgmt_process_data(int mgmt_sk)
-{
- char buf[1024];
- struct mgmt_hdr *hdr = (void *) buf;
- uint16_t len, ev, index;
- ssize_t ret;
-
- ret = read(mgmt_sk, buf, sizeof(buf));
- if (ret < 0) {
- fprintf(stderr, "read: %s\n", strerror(errno));
- return ret;
- }
-
- if (ret < MGMT_HDR_SIZE) {
- fprintf(stderr, "Too small mgmt packet (%zd bytes)\n", ret);
- return 0;
- }
-
- ev = bt_get_le16(&hdr->opcode);
- index = bt_get_le16(&hdr->index);
- len = bt_get_le16(&hdr->len);
-
- if (monitor)
- printf("event 0x%04x len 0x%04x index 0x%04x\n", ev, len, index);
-
- if (ret != MGMT_HDR_SIZE + len) {
- fprintf(stderr, "Packet length mismatch. ret %zd len %u",
- ret, len);
- return 0;
- }
-
- mgmt_handle_event(mgmt_sk, ev, index, buf + MGMT_HDR_SIZE, len);
-
- return 0;
-}
-
-static void cmd_monitor(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- printf("Monitoring mgmt events...\n");
- monitor = true;
-}
-
-static void version_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- struct mgmt_rp_read_version *rp = rsp;
-
- if (status != 0) {
- fprintf(stderr, "Reading mgmt version failed with status"
- " 0x%02x (%s)\n", status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small version reply (%u bytes)\n", len);
- exit(EXIT_FAILURE);
- }
-
- printf("MGMT Version %u, revision %u\n", rp->version,
- bt_get_le16(&rp->revision));
-
- exit(EXIT_SUCCESS);
-}
-
-static void cmd_version(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE,
- NULL, 0, version_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send read_version cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void commands_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- struct mgmt_rp_read_commands *rp = rsp;
- uint16_t num_commands, num_events, *opcode;
- size_t expected_len;
- int i;
-
- if (status != 0) {
- fprintf(stderr, "Reading supported commands failed with status"
- " 0x%02x (%s)\n", status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small commands reply (%u bytes)\n", len);
- exit(EXIT_FAILURE);
- }
-
- num_commands = bt_get_le16(&rp->num_commands);
- num_events = bt_get_le16(&rp->num_events);
-
- expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
- num_events * sizeof(uint16_t);
-
- if (len < expected_len) {
- fprintf(stderr, "Too small commands reply (%u != %zu)\n",
- len, expected_len);
- exit(EXIT_FAILURE);
- }
-
- opcode = rp->opcodes;
-
- printf("%u commands:\n", num_commands);
- for (i = 0; i < num_commands; i++) {
- uint16_t op = bt_get_le16(opcode++);
- printf("\t%s (0x%04x)\n", mgmt_opstr(op), op);
- }
-
- printf("%u events:\n", num_events);
- for (i = 0; i < num_events; i++) {
- uint16_t ev = bt_get_le16(opcode++);
- printf("\t%s (0x%04x)\n", mgmt_evstr(ev), ev);
- }
-
- exit(EXIT_SUCCESS);
-}
-
-static void cmd_commands(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE,
- NULL, 0, commands_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send read_commands cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void info_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- struct mgmt_rp_read_info *rp = rsp;
- char addr[18];
-
- if (status != 0) {
- fprintf(stderr,
- "Reading hci%u info failed with status 0x%02x (%s)\n",
- id, status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small info reply (%u bytes)\n", len);
- exit(EXIT_FAILURE);
- }
-
- ba2str(&rp->bdaddr, addr);
- printf("hci%u:\taddr %s version %u manufacturer %u"
- " class 0x%02x%02x%02x\n",
- id, addr, rp->version, bt_get_le16(&rp->manufacturer),
- rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
-
- printf("\tsupported settings: ");
- print_settings(bt_get_le32(&rp->supported_settings));
-
- printf("\n\tcurrent settings: ");
- print_settings(bt_get_le32(&rp->current_settings));
-
- printf("\n\tname %s\n", rp->name);
- printf("\tshort name %s\n", rp->short_name);
-
- if (pending == NULL)
- exit(EXIT_SUCCESS);
-}
-
-static void index_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- struct mgmt_rp_read_index_list *rp = rsp;
- uint16_t count;
- unsigned int i;
-
- if (status != 0) {
- fprintf(stderr,
- "Reading index list failed with status 0x%02x (%s)\n",
- status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small index list reply (%u bytes)\n",
- len);
- exit(EXIT_FAILURE);
- }
-
- count = bt_get_le16(&rp->num_controllers);
-
- if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
- fprintf(stderr,
- "Index count (%u) doesn't match reply length (%u)\n",
- count, len);
- exit(EXIT_FAILURE);
- }
-
- if (monitor)
- printf("Index list with %u item%s\n",
- count, count > 1 ? "s" : "");
-
- if (count == 0)
- exit(EXIT_SUCCESS);
-
- if (monitor && count > 0)
- printf("\t");
-
- for (i = 0; i < count; i++) {
- uint16_t index;
-
- index = bt_get_le16(&rp->index[i]);
-
- if (monitor)
- printf("hci%u ", index);
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
- 0, info_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send read_info cmd\n");
- exit(EXIT_FAILURE);
- }
- }
-
- if (monitor && count > 0)
- printf("\n");
-}
-
-static void cmd_info(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- if (index == MGMT_INDEX_NONE) {
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INDEX_LIST,
- MGMT_INDEX_NONE, NULL, 0,
- index_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send index_list cmd\n");
- exit(EXIT_FAILURE);
- }
-
- return;
- }
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
- 0, info_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send read_info cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void setting_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- uint32_t *rp = rsp;
-
- if (status != 0) {
- fprintf(stderr,
- "%s for hci%u failed with status 0x%02x (%s)\n",
- mgmt_opstr(op), id, status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small %s response (%u bytes)\n",
- mgmt_opstr(op), len);
- exit(EXIT_FAILURE);
- }
-
- printf("hci%u %s complete, settings: ", id, mgmt_opstr(op));
- print_settings(bt_get_le32(rp));
- printf("\n");
-
- exit(EXIT_SUCCESS);
-}
-
-static void cmd_setting(int mgmt_sk, uint16_t index, uint16_t op,
- int argc, char **argv)
-{
- uint8_t val;
-
- if (argc < 2) {
- printf("Specify \"on\" or \"off\"\n");
- exit(EXIT_FAILURE);
- }
-
- if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
- val = 1;
- else if (strcasecmp(argv[1], "off") == 0)
- val = 0;
- else
- val = atoi(argv[1]);
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- if (mgmt_send_cmd(mgmt_sk, op, index, &val, sizeof(val),
- setting_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send %s cmd\n", mgmt_opstr(op));
- exit(EXIT_FAILURE);
- }
-}
-
-static void cmd_power(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- cmd_setting(mgmt_sk, index, MGMT_OP_SET_POWERED, argc, argv);
-}
-
-static void cmd_discov(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_set_discoverable cp;
-
- if (argc < 2) {
- printf("Usage: btmgmt %s <yes/no> [timeout]\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- memset(&cp, 0, sizeof(cp));
-
- if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
- cp.val = 1;
- else if (strcasecmp(argv[1], "off") == 0)
- cp.val = 0;
- else
- cp.val = atoi(argv[1]);
-
- if (argc > 2)
- cp.timeout = htobs(atoi(argv[2]));
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DISCOVERABLE, index,
- &cp, sizeof(cp), setting_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send set_discoverable cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void cmd_connectable(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- cmd_setting(mgmt_sk, index, MGMT_OP_SET_CONNECTABLE, argc, argv);
-}
-
-static void cmd_pairable(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- cmd_setting(mgmt_sk, index, MGMT_OP_SET_PAIRABLE, argc, argv);
-}
-
-static void cmd_linksec(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- cmd_setting(mgmt_sk, index, MGMT_OP_SET_LINK_SECURITY, argc, argv);
-}
-
-static void cmd_ssp(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- cmd_setting(mgmt_sk, index, MGMT_OP_SET_SSP, argc, argv);
-}
-
-static void cmd_hs(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- cmd_setting(mgmt_sk, index, MGMT_OP_SET_HS, argc, argv);
-}
-
-static void cmd_le(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- cmd_setting(mgmt_sk, index, MGMT_OP_SET_LE, argc, argv);
-}
-
-static void class_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- struct mgmt_ev_class_of_dev_changed *rp = rsp;
-
- if (len == 0 && status != 0) {
- fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
- mgmt_opstr(op), status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- if (len != sizeof(*rp)) {
- fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
- exit(EXIT_FAILURE);
- }
-
- printf("%s succeeded. Class 0x%02x%02x%02x\n", mgmt_opstr(op),
- rp->class_of_dev[2], rp->class_of_dev[1], rp->class_of_dev[0]);
-
- exit(EXIT_SUCCESS);
-}
-
-static void cmd_class(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- uint8_t class[2];
-
- if (argc < 3) {
- printf("Usage: btmgmt %s <major> <minor>\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- class[0] = atoi(argv[1]);
- class[1] = atoi(argv[2]);
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEV_CLASS, index,
- class, sizeof(class), class_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send set_dev_class cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void disconnect_rsp(int mgmt_sk, uint16_t op, uint16_t id,
- uint8_t status, void *rsp, uint16_t len,
- void *user_data)
-{
- struct mgmt_rp_disconnect *rp = rsp;
- char addr[18];
-
- if (len == 0 && status != 0) {
- fprintf(stderr, "Disconnect failed with status 0x%02x (%s)\n",
- status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- if (len != sizeof(*rp)) {
- fprintf(stderr, "Invalid disconnect response length (%u)\n",
- len);
- exit(EXIT_FAILURE);
- }
-
- ba2str(&rp->addr.bdaddr, addr);
-
- if (status == 0) {
- printf("%s disconnected\n", addr);
- exit(EXIT_SUCCESS);
- } else {
- fprintf(stderr,
- "Disconnecting %s failed with status 0x%02x (%s)\n",
- addr, status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-}
-
-static void cmd_disconnect(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_disconnect cp;
-
- if (argc < 2) {
- printf("Usage: btmgmt %s <address>\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- str2ba(argv[1], &cp.addr.bdaddr);
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_DISCONNECT, index,
- &cp, sizeof(cp), disconnect_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send disconnect cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void con_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- struct mgmt_rp_get_connections *rp = rsp;
- uint16_t count, i;
-
- if (len < sizeof(*rp)) {
- fprintf(stderr, "Too small (%u bytes) get_connections rsp\n",
- len);
- exit(EXIT_FAILURE);
- }
-
- count = bt_get_le16(&rp->conn_count);
- if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) {
- fprintf(stderr, "Invalid get_connections length "
- " (count=%u, len=%u)\n", count, len);
- exit(EXIT_FAILURE);
- }
-
- for (i = 0; i < count; i++) {
- char addr[18];
-
- ba2str(&rp->addr[i].bdaddr, addr);
-
- printf("%s type %s\n", addr, typestr(rp->addr[i].type));
- }
-
- exit(EXIT_SUCCESS);
-}
-
-static void cmd_con(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_GET_CONNECTIONS, index, NULL, 0,
- con_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send get_connections cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void find_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- if (status != 0) {
- fprintf(stderr,
- "Unable to start discovery. status 0x%02x (%s)\n",
- status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- printf("Discovery started\n");
- discovery = true;
-}
-
-static void find_usage(void)
-{
- printf("Usage: btmgmt find [-l|-b]>\n");
-}
-
-static struct option find_options[] = {
- { "help", 0, 0, 'h' },
- { "le-only", 1, 0, 'l' },
- { "bredr-only", 1, 0, 'b' },
- { 0, 0, 0, 0 }
-};
-
-static void cmd_find(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_start_discovery cp;
- uint8_t type;
- int opt;
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- type = 0;
- hci_set_bit(BDADDR_BREDR, &type);
- hci_set_bit(BDADDR_LE_PUBLIC, &type);
- hci_set_bit(BDADDR_LE_RANDOM, &type);
-
- while ((opt = getopt_long(argc, argv, "+lbh", find_options,
- NULL)) != -1) {
- switch (opt) {
- case 'l':
- hci_clear_bit(BDADDR_BREDR, &type);
- hci_set_bit(BDADDR_LE_PUBLIC, &type);
- hci_set_bit(BDADDR_LE_RANDOM, &type);
- break;
- case 'b':
- hci_set_bit(BDADDR_BREDR, &type);
- hci_clear_bit(BDADDR_LE_PUBLIC, &type);
- hci_clear_bit(BDADDR_LE_RANDOM, &type);
- break;
- case 'h':
- default:
- find_usage();
- exit(EXIT_SUCCESS);
- }
- }
-
- argc -= optind;
- argv += optind;
- optind = 0;
-
- memset(&cp, 0, sizeof(cp));
- cp.type = type;
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_START_DISCOVERY, index,
- &cp, sizeof(cp), find_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send start_discovery cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void name_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- if (status != 0) {
- fprintf(stderr, "Unable to set local name. status 0x%02x (%s)",
- status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- exit(EXIT_SUCCESS);
-}
-
-static void cmd_name(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_set_local_name cp;
-
- if (argc < 2) {
- printf("Usage: btmgmt %s <name> [shortname]\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- memset(&cp, 0, sizeof(cp));
- strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH);
- if (argc > 2)
- strncpy((char *) cp.short_name, argv[2],
- MGMT_MAX_SHORT_NAME_LENGTH);
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_LOCAL_NAME, index,
- &cp, sizeof(cp), name_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send set_name cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void pair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- struct mgmt_rp_pair_device *rp = rsp;
- char addr[18];
-
- if (len == 0 && status != 0) {
- fprintf(stderr, "Pairing failed with status 0x%02x (%s)\n",
- status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- if (len != sizeof(*rp)) {
- fprintf(stderr, "Unexpected pair_rsp len %u\n", len);
- exit(EXIT_FAILURE);
- }
-
- ba2str(&rp->addr.bdaddr, addr);
-
- if (status != 0) {
- fprintf(stderr,
- "Pairing with %s (%s) failed. status 0x%02x (%s)\n",
- addr, typestr(rp->addr.type), status,
- mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- printf("Paired with %s\n", addr);
-
- exit(EXIT_SUCCESS);
-}
-
-static void pair_usage(void)
-{
- printf("Usage: btmgmt pair [-c cap] [-t type] <remote address>\n");
-}
-
-static struct option pair_options[] = {
- { "help", 0, 0, 'h' },
- { "capability", 1, 0, 'c' },
- { "type", 1, 0, 't' },
- { 0, 0, 0, 0 }
-};
-
-static void cmd_pair(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_pair_device cp;
- uint8_t cap = 0x01;
- uint8_t type = BDADDR_BREDR;
- int opt;
-
- while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options,
- NULL)) != -1) {
- switch (opt) {
- case 'c':
- cap = strtol(optarg, NULL, 0);
- break;
- case 't':
- type = strtol(optarg, NULL, 0);
- break;
- case 'h':
- default:
- pair_usage();
- exit(EXIT_SUCCESS);
- }
- }
-
- argc -= optind;
- argv += optind;
- optind = 0;
-
- if (argc < 1) {
- pair_usage();
- exit(EXIT_FAILURE);
- }
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- memset(&cp, 0, sizeof(cp));
- str2ba(argv[0], &cp.addr.bdaddr);
- cp.addr.type = type;
- cp.io_cap = cap;
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_PAIR_DEVICE, index, &cp, sizeof(cp),
- pair_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send pair_device cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void unpair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- struct mgmt_rp_unpair_device *rp = rsp;
- char addr[18];
-
- if (len == 0 && status != 0) {
- fprintf(stderr, "Unpair device failed. status 0x%02x (%s)\n",
- status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- if (len != sizeof(*rp)) {
- fprintf(stderr, "Unexpected unpair_device_rsp len %u\n", len);
- exit(EXIT_FAILURE);
- }
-
- ba2str(&rp->addr.bdaddr, addr);
-
- if (status != 0) {
- fprintf(stderr,
- "Unpairing %s failed. status 0x%02x (%s)\n",
- addr, status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- printf("%s unpaired\n", addr);
-
- exit(EXIT_SUCCESS);
-}
-
-static void cmd_unpair(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_unpair_device cp;
-
- if (argc < 2) {
- printf("Usage: btmgmt %s <remote address>\n", argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- memset(&cp, 0, sizeof(cp));
- str2ba(argv[1], &cp.addr.bdaddr);
- cp.disconnect = 1;
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNPAIR_DEVICE, index, &cp,
- sizeof(cp), unpair_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send unpair_device cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void keys_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- if (status != 0) {
- fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n",
- status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- printf("Keys successfully loaded\n");
-
- exit(EXIT_SUCCESS);
-}
-
-static void cmd_keys(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_load_link_keys cp;
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- memset(&cp, 0, sizeof(cp));
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_LOAD_LINK_KEYS, index,
- &cp, sizeof(cp), keys_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send load_keys cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void block_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- struct mgmt_addr_info *rp = rsp;
- char addr[18];
-
- if (len == 0 && status != 0) {
- fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
- mgmt_opstr(op), status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- if (len != sizeof(*rp)) {
- fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
- exit(EXIT_FAILURE);
- }
-
- ba2str(&rp->bdaddr, addr);
-
- if (status != 0) {
- fprintf(stderr, "%s %s (%s) failed. status 0x%02x (%s)\n",
- mgmt_opstr(op), addr, typestr(rp->type),
- status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- printf("%s %s succeeded\n", mgmt_opstr(op), addr);
-
- exit(EXIT_SUCCESS);
-}
-
-static void block_usage(void)
-{
- printf("Usage: btmgmt block [-t type] <remote address>\n");
-}
-
-static struct option block_options[] = {
- { "help", 0, 0, 'h' },
- { "type", 1, 0, 't' },
- { 0, 0, 0, 0 }
-};
-
-static void cmd_block(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_block_device cp;
- uint8_t type = BDADDR_BREDR;
- int opt;
-
- while ((opt = getopt_long(argc, argv, "+t:h", block_options,
- NULL)) != -1) {
- switch (opt) {
- case 't':
- type = strtol(optarg, NULL, 0);
- break;
- case 'h':
- default:
- block_usage();
- exit(EXIT_SUCCESS);
- }
- }
-
- argc -= optind;
- argv += optind;
- optind = 0;
-
- if (argc < 1) {
- block_usage();
- exit(EXIT_FAILURE);
- }
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- memset(&cp, 0, sizeof(cp));
- str2ba(argv[0], &cp.addr.bdaddr);
- cp.addr.type = type;
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_BLOCK_DEVICE, index,
- &cp, sizeof(cp), block_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send block_device cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void unblock_usage(void)
-{
- printf("Usage: btmgmt unblock [-t type] <remote address>\n");
-}
-
-static void cmd_unblock(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_unblock_device cp;
- uint8_t type = BDADDR_BREDR;
- int opt;
-
- while ((opt = getopt_long(argc, argv, "+t:h", block_options,
- NULL)) != -1) {
- switch (opt) {
- case 't':
- type = strtol(optarg, NULL, 0);
- break;
- case 'h':
- default:
- unblock_usage();
- exit(EXIT_SUCCESS);
- }
- }
-
- argc -= optind;
- argv += optind;
- optind = 0;
-
- if (argc < 1) {
- unblock_usage();
- exit(EXIT_FAILURE);
- }
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- memset(&cp, 0, sizeof(cp));
- str2ba(argv[0], &cp.addr.bdaddr);
- cp.addr.type = type;
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNBLOCK_DEVICE, index,
- &cp, sizeof(cp), block_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send unblock_device cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
-{
- if (uuid->type == SDP_UUID16)
- sdp_uuid16_to_uuid128(uuid128, uuid);
- else if (uuid->type == SDP_UUID32)
- sdp_uuid32_to_uuid128(uuid128, uuid);
- else
- memcpy(uuid128, uuid, sizeof(*uuid));
-}
-
-static void cmd_add_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_add_uuid cp;
- uint128_t uint128;
- uuid_t uuid, uuid128;
-
- if (argc < 3) {
- printf("UUID and service hint needed\n");
- exit(EXIT_FAILURE);
- }
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- if (bt_string2uuid(&uuid, argv[1]) < 0) {
- printf("Invalid UUID: %s\n", argv[1]);
- exit(EXIT_FAILURE);
- }
-
- memset(&cp, 0, sizeof(cp));
-
- uuid_to_uuid128(&uuid128, &uuid);
- ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
- htob128(&uint128, (uint128_t *) cp.uuid);
-
- cp.svc_hint = atoi(argv[2]);
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_ADD_UUID, index,
- &cp, sizeof(cp), class_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send add_uuid cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void cmd_remove_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_remove_uuid cp;
- uint128_t uint128;
- uuid_t uuid, uuid128;
-
- if (argc < 2) {
- printf("UUID needed\n");
- exit(EXIT_FAILURE);
- }
-
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- if (bt_string2uuid(&uuid, argv[1]) < 0) {
- printf("Invalid UUID: %s\n", argv[1]);
- exit(EXIT_FAILURE);
- }
-
- memset(&cp, 0, sizeof(cp));
-
- uuid_to_uuid128(&uuid128, &uuid);
- ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
- htob128(&uint128, (uint128_t *) cp.uuid);
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_REMOVE_UUID, index,
- &cp, sizeof(cp), class_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send remove_uuid cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static void cmd_clr_uuids(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- char *uuid_any = "00000000-0000-0000-0000-000000000000";
- char *rm_argv[] = { "rm-uuid", uuid_any, NULL };
-
- cmd_remove_uuid(mgmt_sk, index, 2, rm_argv);
-}
-
-static void did_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
- void *rsp, uint16_t len, void *user_data)
-{
- if (status != 0) {
- fprintf(stderr, "Set Device ID failed with status 0x%02x (%s)\n",
- status, mgmt_errstr(status));
- exit(EXIT_FAILURE);
- }
-
- printf("Device ID successfully set\n");
-
- exit(EXIT_SUCCESS);
-}
-
-static void did_usage(void)
-{
- printf("Usage: btmgmt did <source>:<vendor>:<product>:<version>\n");
- printf(" possible source values: bluetooth, usb\n");
-}
-
-static void cmd_did(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
- struct mgmt_cp_set_device_id cp;
- uint16_t vendor, product, version , source;
- int result;
-
- if (argc < 2) {
- did_usage();
- exit(EXIT_FAILURE);
- }
-
- result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product,
- &version);
- if (result == 3) {
- source = 0x0001;
- goto done;
- }
-
- result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product,
- &version);
- if (result == 3) {
- source = 0x0002;
- goto done;
- }
-
- did_usage();
- exit(EXIT_FAILURE);
-
-done:
- if (index == MGMT_INDEX_NONE)
- index = 0;
-
- cp.source = htobs(source);
- cp.vendor = htobs(vendor);
- cp.product = htobs(product);
- cp.version = htobs(version);
-
- if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEVICE_ID, index,
- &cp, sizeof(cp), did_rsp, NULL) < 0) {
- fprintf(stderr, "Unable to send set_dev_class cmd\n");
- exit(EXIT_FAILURE);
- }
-}
-
-static struct {
- char *cmd;
- void (*func)(int mgmt_sk, uint16_t index, int argc, char **argv);
- char *doc;
-} command[] = {
- { "monitor", cmd_monitor, "Monitor events" },
- { "version", cmd_version, "Get the MGMT Version" },
- { "commands", cmd_commands, "List supported commands" },
- { "info", cmd_info, "Show controller info" },
- { "power", cmd_power, "Toggle powered state" },
- { "discov", cmd_discov, "Toggle discoverable state" },
- { "connectable",cmd_connectable,"Toggle connectable state" },
- { "pairable", cmd_pairable, "Toggle pairable state" },
- { "linksec", cmd_linksec, "Toggle link level security" },
- { "ssp", cmd_ssp, "Toggle SSP mode" },
- { "hs", cmd_hs, "Toggle HS Support" },
- { "le", cmd_le, "Toggle LE Support" },
- { "class", cmd_class, "Set device major/minor class" },
- { "disconnect", cmd_disconnect, "Disconnect device" },
- { "con", cmd_con, "List connections" },
- { "find", cmd_find, "Discover nearby devices" },
- { "name", cmd_name, "Set local name" },
- { "pair", cmd_pair, "Pair with a remote device" },
- { "unpair", cmd_unpair, "Unpair device" },
- { "keys", cmd_keys, "Load Keys" },
- { "block", cmd_block, "Block Device" },
- { "unblock", cmd_unblock, "Unblock Device" },
- { "add-uuid", cmd_add_uuid, "Add UUID" },
- { "rm-uuid", cmd_add_uuid, "Remove UUID" },
- { "clr-uuids", cmd_clr_uuids, "Clear UUIDs", },
- { "did", cmd_did, "Set Device ID", },
- { NULL, NULL, 0 }
-};
-
-static void usage(void)
-{
- int i;
-
- printf("btmgmt ver %s\n", VERSION);
- printf("Usage:\n"
- "\tbtmgmt [options] <command> [command parameters]\n");
-
- printf("Options:\n"
- "\t--index <id>\tSpecify adapter index\n"
- "\t--verbose\tEnable extra logging\n"
- "\t--help\tDisplay help\n");
-
- printf("Commands:\n");
- for (i = 0; command[i].cmd; i++)
- printf("\t%-15s\t%s\n", command[i].cmd, command[i].doc);
-
- printf("\n"
- "For more information on the usage of each command use:\n"
- "\tbtmgmt <command> --help\n" );
-}
-
-static struct option main_options[] = {
- { "index", 1, 0, 'i' },
- { "verbose", 0, 0, 'v' },
- { "help", 0, 0, 'h' },
- { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
- int opt, i, mgmt_sk;
- uint16_t index = MGMT_INDEX_NONE;
- struct pollfd pollfd;
-
- while ((opt = getopt_long(argc, argv, "+hvi:",
- main_options, NULL)) != -1) {
- switch (opt) {
- case 'i':
- if (strlen(optarg) > 3 &&
- strncasecmp(optarg, "hci", 3) == 0)
- index = atoi(&optarg[4]);
- else
- index = atoi(optarg);
- break;
- case 'v':
- monitor = true;
- break;
- case 'h':
- default:
- usage();
- return 0;
- }
- }
-
- argc -= optind;
- argv += optind;
- optind = 0;
-
- if (argc < 1) {
- usage();
- return 0;
- }
-
- mgmt_sk = mgmt_open();
- if (mgmt_sk < 0) {
- fprintf(stderr, "Unable to open mgmt socket\n");
- return -1;
- }
-
- for (i = 0; command[i].cmd; i++) {
- if (strcmp(command[i].cmd, argv[0]) != 0)
- continue;
-
- command[i].func(mgmt_sk, index, argc, argv);
- break;
- }
-
- if (command[i].cmd == NULL) {
- fprintf(stderr, "Unknown command: %s\n", argv[0]);
- close(mgmt_sk);
- return -1;
- }
-
- pollfd.fd = mgmt_sk;
- pollfd.events = POLLIN;
- pollfd.revents = 0;
-
- while (poll(&pollfd, 1, -1) >= 0) {
- if (pollfd.revents & (POLLHUP | POLLERR | POLLNVAL))
- break;
-
- if (pollfd.revents & POLLIN)
- mgmt_process_data(mgmt_sk);
-
- pollfd.revents = 0;
- }
-
- close(mgmt_sk);
-
- return 0;
-}
diff --git a/tools/mgmt/main.c b/tools/mgmt/main.c
new file mode 100644
index 0000000..b2d6c3c
--- /dev/null
+++ b/tools/mgmt/main.c
@@ -0,0 +1,1933 @@
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 Intel Corporation. All rights reserved.
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/mgmt.h>
+
+#include <glib.h>
+#include "glib-helper.h"
+
+static bool monitor = false;
+static bool discovery = false;
+static bool resolve_names = true;
+
+typedef void (*cmd_cb)(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data);
+
+static struct pending_cmd {
+ uint16_t op;
+ uint16_t id;
+ cmd_cb cb;
+ void *user_data;
+ struct pending_cmd *next;
+} *pending = NULL;
+
+static int mgmt_send_cmd(int mgmt_sk, uint16_t op, uint16_t id, void *data,
+ size_t len, cmd_cb func, void *user_data)
+{
+ char buf[1024];
+ struct pending_cmd *cmd;
+ struct mgmt_hdr *hdr = (void *) buf;
+
+ if (len + MGMT_HDR_SIZE > sizeof(buf))
+ return -EINVAL;
+
+ cmd = calloc(1, sizeof(struct pending_cmd));
+ if (cmd == NULL)
+ return -errno;
+
+ cmd->op = op;
+ cmd->id = id;
+ cmd->cb = func;
+ cmd->user_data = user_data;
+
+ memset(buf, 0, sizeof(buf));
+ hdr->opcode = htobs(op);
+ hdr->index = htobs(id);
+ hdr->len = htobs(len);
+ memcpy(buf + MGMT_HDR_SIZE, data, len);
+
+ if (write(mgmt_sk, buf, MGMT_HDR_SIZE + len) < 0) {
+ fprintf(stderr, "Unable to write to socket: %s\n",
+ strerror(errno));
+ free(cmd);
+ return -1;
+ }
+
+ cmd->next = pending;
+ pending = cmd;
+
+ return 0;
+}
+
+static int mgmt_open(void)
+{
+ struct sockaddr_hci addr;
+ int sk;
+
+ sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (sk < 0) {
+ fprintf(stderr, "socket: %s\n", strerror(errno));
+ return sk;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.hci_family = AF_BLUETOOTH;
+ addr.hci_dev = HCI_DEV_NONE;
+ addr.hci_channel = HCI_CHANNEL_CONTROL;
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ fprintf(stderr, "bind: %s\n", strerror(errno));
+ close(sk);
+ return -1;
+ }
+
+ return sk;
+}
+
+static void mgmt_check_pending(int mgmt_sk, uint16_t op, uint16_t index,
+ uint16_t status, void *data, uint16_t len)
+{
+ struct pending_cmd *c, *prev;
+
+ for (c = pending, prev = NULL; c != NULL; prev = c, c = c->next) {
+ if (c->op != op)
+ continue;
+ if (c->id != index)
+ continue;
+
+ if (c == pending)
+ pending = c->next;
+ else
+ prev->next = c->next;
+
+ c->cb(mgmt_sk, op, index, status, data, len, c->user_data);
+
+ free(c);
+ break;
+ }
+}
+
+static int mgmt_cmd_complete(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_cmd_complete *ev, uint16_t len)
+{
+ uint16_t op;
+
+ if (len < sizeof(*ev)) {
+ fprintf(stderr, "Too short (%u bytes) cmd complete event\n",
+ len);
+ return -EINVAL;
+ }
+
+ op = bt_get_le16(&ev->opcode);
+
+ len -= sizeof(*ev);
+
+ if (monitor)
+ printf("%s complete, opcode 0x%04x len %u\n", mgmt_opstr(op),
+ op, len);
+
+ mgmt_check_pending(mgmt_sk, op, index, ev->status, ev->data, len);
+
+ return 0;
+}
+
+static int mgmt_cmd_status(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_cmd_status *ev, uint16_t len)
+{
+ uint16_t opcode;
+
+ if (len < sizeof(*ev)) {
+ fprintf(stderr, "Too short (%u bytes) cmd status event\n",
+ len);
+ return -EINVAL;
+ }
+
+ opcode = bt_get_le16(&ev->opcode);
+
+ if (monitor)
+ printf("cmd status, opcode 0x%04x status 0x%02x (%s)\n",
+ opcode, ev->status, mgmt_errstr(ev->status));
+
+ if (ev->status != 0)
+ mgmt_check_pending(mgmt_sk, opcode, index, ev->status,
+ NULL, 0);
+
+ return 0;
+}
+
+static int mgmt_controller_error(uint16_t index,
+ struct mgmt_ev_controller_error *ev,
+ uint16_t len)
+{
+ if (len < sizeof(*ev)) {
+ fprintf(stderr,
+ "Too short (%u bytes) controller error event\n", len);
+ return -EINVAL;
+ }
+
+ if (monitor)
+ printf("hci%u error 0x%02x\n", index, ev->error_code);
+
+ return 0;
+}
+
+static int mgmt_index_added(int mgmt_sk, uint16_t index)
+{
+ if (monitor)
+ printf("hci%u added\n", index);
+ return 0;
+}
+
+static int mgmt_index_removed(int mgmt_sk, uint16_t index)
+{
+ if (monitor)
+ printf("hci%u removed\n", index);
+ return 0;
+}
+
+static const char *settings_str[] = {
+ "powered",
+ "connectable",
+ "fast-connectable",
+ "discoverable",
+ "pairable",
+ "link-security",
+ "ssp",
+ "br/edr",
+ "hs",
+ "le" ,
+};
+
+static void print_settings(uint32_t settings)
+{
+ unsigned i;
+
+ for (i = 0; i < NELEM(settings_str); i++) {
+ if ((settings & (1 << i)) != 0)
+ printf("%s ", settings_str[i]);
+ }
+}
+
+static int mgmt_new_settings(int mgmt_sk, uint16_t index,
+ uint32_t *ev, uint16_t len)
+{
+ if (len < sizeof(*ev)) {
+ fprintf(stderr, "Too short new_settings event (%u)\n", len);
+ return -EINVAL;
+ }
+
+ if (monitor) {
+ printf("hci%u new_settings: ", index);
+ print_settings(bt_get_le32(ev));
+ printf("\n");
+ }
+
+ return 0;
+}
+
+static int mgmt_discovering(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_discovering *ev, uint16_t len)
+{
+ if (len < sizeof(*ev)) {
+ fprintf(stderr, "Too short (%u bytes) discovering event\n",
+ len);
+ return -EINVAL;
+ }
+
+ if (ev->discovering == 0 && discovery)
+ exit(EXIT_SUCCESS);
+
+ if (monitor)
+ printf("hci%u type %u discovering %s\n", index,
+ ev->type, ev->discovering ? "on" : "off");
+
+ return 0;
+}
+
+static int mgmt_new_link_key(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_new_link_key *ev, uint16_t len)
+{
+
+ if (len != sizeof(*ev)) {
+ fprintf(stderr, "Invalid new_link_key length (%u bytes)\n",
+ len);
+ return -EINVAL;
+ }
+
+ if (monitor) {
+ char addr[18];
+ ba2str(&ev->key.addr.bdaddr, addr);
+ printf("hci%u new_link_key %s type 0x%02x pin_len %d "
+ "store_hint %u\n", index, addr, ev->key.type,
+ ev->key.pin_len, ev->store_hint);
+ }
+
+ return 0;
+}
+
+static const char *typestr(uint8_t type)
+{
+ const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
+
+ if (type <= BDADDR_LE_RANDOM)
+ return str[type];
+
+ return "(unknown)";
+}
+
+static int mgmt_connected(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_device_connected *ev,
+ uint16_t len)
+{
+ uint16_t eir_len;
+
+ if (len < sizeof(*ev)) {
+ fprintf(stderr,
+ "Invalid connected event length (%u bytes)\n", len);
+ return -EINVAL;
+ }
+
+ eir_len = bt_get_le16(&ev->eir_len);
+ if (len != sizeof(*ev) + eir_len) {
+ fprintf(stderr, "Invalid connected event length "
+ "(%u bytes, eir_len %u bytes)\n", len, eir_len);
+ return -EINVAL;
+ }
+
+ if (monitor) {
+ char addr[18];
+ ba2str(&ev->addr.bdaddr, addr);
+ printf("hci%u %s type %s connected eir_len %u\n", index, addr,
+ typestr(ev->addr.type), eir_len);
+ }
+
+ return 0;
+}
+
+static int mgmt_disconnected(int mgmt_sk, uint16_t index,
+ struct mgmt_addr_info *ev, uint16_t len)
+{
+ if (len != sizeof(*ev)) {
+ fprintf(stderr,
+ "Invalid disconnected event length (%u bytes)\n", len);
+ return -EINVAL;
+ }
+
+ if (monitor) {
+ char addr[18];
+ ba2str(&ev->bdaddr, addr);
+ printf("hci%u %s type %s disconnected\n", index, addr,
+ typestr(ev->type));
+ }
+
+ return 0;
+}
+
+static int mgmt_conn_failed(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_connect_failed *ev,
+ uint16_t len)
+{
+ if (len != sizeof(*ev)) {
+ fprintf(stderr,
+ "Invalid connect_failed event length (%u bytes)\n", len);
+ return -EINVAL;
+ }
+
+ if (monitor) {
+ char addr[18];
+ ba2str(&ev->addr.bdaddr, addr);
+ printf("hci%u %s type %s connect failed (status 0x%02x, %s)\n",
+ index, addr, typestr(ev->addr.type), ev->status,
+ mgmt_errstr(ev->status));
+ }
+
+ return 0;
+}
+
+static int mgmt_auth_failed(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_auth_failed *ev,
+ uint16_t len)
+{
+ if (len != sizeof(*ev)) {
+ fprintf(stderr,
+ "Invalid auth_failed event length (%u bytes)\n", len);
+ return -EINVAL;
+ }
+
+ if (monitor) {
+ char addr[18];
+ ba2str(&ev->addr.bdaddr, addr);
+ printf("hci%u %s auth failed with status 0x%02x (%s)\n",
+ index, addr, ev->status, mgmt_errstr(ev->status));
+ }
+
+ return 0;
+}
+
+static int mgmt_name_changed(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_local_name_changed *ev,
+ uint16_t len)
+{
+ if (len != sizeof(*ev)) {
+ fprintf(stderr,
+ "Invalid local_name_changed length (%u bytes)\n", len);
+ return -EINVAL;
+ }
+
+ if (monitor)
+ printf("hci%u name changed: %s\n", index, ev->name);
+
+ return 0;
+}
+
+static void confirm_name_rsp(int mgmt_sk, uint16_t op, uint16_t id,
+ uint8_t status, void *rsp, uint16_t len,
+ void *user_data)
+{
+ struct mgmt_rp_confirm_name *rp = rsp;
+ char addr[18];
+
+ if (len == 0 && status != 0) {
+ fprintf(stderr,
+ "hci%u confirm_name failed with status 0x%02x (%s)\n",
+ id, status, mgmt_errstr(status));
+ return;
+ }
+
+ if (len != sizeof(*rp)) {
+ fprintf(stderr,
+ "hci%u confirm_name rsp length %u instead of %zu\n",
+ id, len, sizeof(*rp));
+ return;
+ }
+
+ ba2str(&rp->addr.bdaddr, addr);
+
+ if (status != 0)
+ fprintf(stderr,
+ "hci%u confirm_name for %s failed: 0x%02x (%s)\n",
+ id, addr, status, mgmt_errstr(status));
+ else
+ printf("hci%u confirm_name succeeded for %s\n", id, addr);
+}
+
+static int mgmt_device_found(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_device_found *ev, uint16_t len)
+{
+ uint32_t flags;
+ uint16_t eir_len;
+
+ if (len < sizeof(*ev)) {
+ fprintf(stderr,
+ "Too short device_found length (%u bytes)\n", len);
+ return -EINVAL;
+ }
+
+ flags = btohs(ev->flags);
+
+ eir_len = bt_get_le16(&ev->eir_len);
+ if (len != sizeof(*ev) + eir_len) {
+ fprintf(stderr, "dev_found: expected %zu bytes, got %u bytes",
+ sizeof(*ev) + eir_len, len);
+ return -EINVAL;
+ }
+
+ if (monitor || discovery) {
+ char addr[18];
+ ba2str(&ev->addr.bdaddr, addr);
+ printf("hci%u dev_found: %s type %s rssi %d "
+ "flags 0x%04x eir_len %u\n", index, addr,
+ typestr(ev->addr.type), ev->rssi, flags, eir_len);
+ }
+
+ if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) {
+ struct mgmt_cp_confirm_name cp;
+
+ memset(&cp, 0, sizeof(cp));
+ memcpy(&cp.addr, &ev->addr, sizeof(cp.addr));
+ if (resolve_names)
+ cp.name_known = 0;
+ else
+ cp.name_known = 1;
+
+ mgmt_send_cmd(mgmt_sk, MGMT_OP_CONFIRM_NAME, index,
+ &cp, sizeof(cp), confirm_name_rsp,
+ NULL);
+ }
+
+ return 0;
+}
+
+static void pin_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ if (status != 0) {
+ fprintf(stderr,
+ "hci%u PIN Code reply failed with status 0x%02x (%s)",
+ id, status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("hci%u PIN Reply successful\n", id);
+}
+
+static int mgmt_pin_reply(int mgmt_sk, uint16_t index,
+ struct mgmt_addr_info *addr,
+ const char *pin, size_t len)
+{
+ struct mgmt_cp_pin_code_reply cp;
+
+ memset(&cp, 0, sizeof(cp));
+ memcpy(&cp.addr, addr, sizeof(cp.addr));
+ cp.pin_len = len;
+ memcpy(cp.pin_code, pin, len);
+
+ return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_REPLY, index,
+ &cp, sizeof(cp), pin_rsp, NULL);
+}
+
+static void pin_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ if (status != 0) {
+ fprintf(stderr,
+ "hci%u PIN Neg reply failed with status 0x%02x (%s)",
+ id, status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("hci%u PIN Negative Reply successful\n", id);
+}
+
+static int mgmt_pin_neg_reply(int mgmt_sk, uint16_t index,
+ struct mgmt_addr_info *addr)
+{
+ struct mgmt_cp_pin_code_neg_reply cp;
+
+ memset(&cp, 0, sizeof(cp));
+ memcpy(&cp.addr, addr, sizeof(cp.addr));
+
+ return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
+ &cp, sizeof(cp), pin_neg_rsp, NULL);
+}
+
+static int mgmt_request_pin(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_pin_code_request *ev,
+ uint16_t len)
+{
+ char pin[18];
+ size_t pin_len;
+
+ if (len != sizeof(*ev)) {
+ fprintf(stderr,
+ "Invalid pin_code request length (%u bytes)\n", len);
+ return -EINVAL;
+ }
+
+ if (monitor) {
+ char addr[18];
+ ba2str(&ev->addr.bdaddr, addr);
+ printf("hci%u %s request PIN\n", index, addr);
+ }
+
+ printf("PIN Request (press enter to reject) >> ");
+ fflush(stdout);
+
+ memset(pin, 0, sizeof(pin));
+
+ if (fgets(pin, sizeof(pin), stdin) == NULL || pin[0] == '\n')
+ return mgmt_pin_neg_reply(mgmt_sk, index, &ev->addr);
+
+ pin_len = strlen(pin);
+ if (pin[pin_len - 1] == '\n') {
+ pin[pin_len - 1] = '\0';
+ pin_len--;
+ }
+
+ return mgmt_pin_reply(mgmt_sk, index, &ev->addr, pin, pin_len);
+}
+
+static void confirm_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ if (status != 0) {
+ fprintf(stderr,
+ "hci%u User Confirm reply failed. status 0x%02x (%s)",
+ id, status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("hci%u User Confirm Reply successful\n", id);
+}
+
+static int mgmt_confirm_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr)
+{
+ struct mgmt_cp_user_confirm_reply cp;
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.addr.bdaddr, bdaddr);
+
+ return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_REPLY, index,
+ &cp, sizeof(cp), confirm_rsp, NULL);
+}
+
+static void confirm_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id,
+ uint8_t status, void *rsp, uint16_t len,
+ void *user_data)
+{
+ if (status != 0) {
+ fprintf(stderr,
+ "hci%u Confirm Neg reply failed. status 0x%02x (%s)",
+ id, status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("hci%u User Confirm Negative Reply successful\n", id);
+}
+
+static int mgmt_confirm_neg_reply(int mgmt_sk, uint16_t index,
+ bdaddr_t *bdaddr)
+{
+ struct mgmt_cp_user_confirm_reply cp;
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.addr.bdaddr, bdaddr);
+
+ return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_NEG_REPLY, index,
+ &cp, sizeof(cp), confirm_neg_rsp, NULL);
+}
+
+
+static int mgmt_user_confirm(int mgmt_sk, uint16_t index,
+ struct mgmt_ev_user_confirm_request *ev,
+ uint16_t len)
+{
+ char rsp[5];
+ size_t rsp_len;
+ uint32_t val;
+ char addr[18];
+
+ if (len != sizeof(*ev)) {
+ fprintf(stderr,
+ "Invalid user_confirm request length (%u)\n", len);
+ return -EINVAL;
+ }
+
+ ba2str(&ev->addr.bdaddr, addr);
+ val = bt_get_le32(&ev->value);
+
+ if (monitor)
+ printf("hci%u %s User Confirm %06u hint %u\n", index, addr,
+ val, ev->confirm_hint);
+
+ if (ev->confirm_hint)
+ printf("Accept pairing with %s (yes/no) >> ", addr);
+ else
+ printf("Confirm value %06u for %s (yes/no) >> ", val, addr);
+
+ fflush(stdout);
+
+ memset(rsp, 0, sizeof(rsp));
+
+ if (fgets(rsp, sizeof(rsp), stdin) == NULL || rsp[0] == '\n')
+ return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr);
+
+ rsp_len = strlen(rsp);
+ if (rsp[rsp_len - 1] == '\n') {
+ rsp[rsp_len - 1] = '\0';
+ rsp_len--;
+ }
+
+ if (rsp[0] == 'y' || rsp[0] == 'Y')
+ return mgmt_confirm_reply(mgmt_sk, index, &ev->addr.bdaddr);
+ else
+ return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr);
+}
+
+static int mgmt_handle_event(int mgmt_sk, uint16_t ev, uint16_t index,
+ void *data, uint16_t len)
+{
+ if (monitor)
+ printf("event: %s\n", mgmt_evstr(ev));
+
+ switch (ev) {
+ case MGMT_EV_CMD_COMPLETE:
+ return mgmt_cmd_complete(mgmt_sk, index, data, len);
+ case MGMT_EV_CMD_STATUS:
+ return mgmt_cmd_status(mgmt_sk, index, data, len);
+ case MGMT_EV_CONTROLLER_ERROR:
+ return mgmt_controller_error(index, data, len);
+ case MGMT_EV_INDEX_ADDED:
+ return mgmt_index_added(mgmt_sk, index);
+ case MGMT_EV_INDEX_REMOVED:
+ return mgmt_index_removed(mgmt_sk, index);
+ case MGMT_EV_NEW_SETTINGS:
+ return mgmt_new_settings(mgmt_sk, index, data, len);
+ case MGMT_EV_DISCOVERING:
+ return mgmt_discovering(mgmt_sk, index, data, len);
+ case MGMT_EV_NEW_LINK_KEY:
+ return mgmt_new_link_key(mgmt_sk, index, data, len);
+ case MGMT_EV_DEVICE_CONNECTED:
+ return mgmt_connected(mgmt_sk, index, data, len);
+ case MGMT_EV_DEVICE_DISCONNECTED:
+ return mgmt_disconnected(mgmt_sk, index, data, len);
+ case MGMT_EV_CONNECT_FAILED:
+ return mgmt_conn_failed(mgmt_sk, index, data, len);
+ case MGMT_EV_AUTH_FAILED:
+ return mgmt_auth_failed(mgmt_sk, index, data, len);
+ case MGMT_EV_LOCAL_NAME_CHANGED:
+ return mgmt_name_changed(mgmt_sk, index, data, len);
+ case MGMT_EV_DEVICE_FOUND:
+ return mgmt_device_found(mgmt_sk, index, data, len);
+ case MGMT_EV_PIN_CODE_REQUEST:
+ return mgmt_request_pin(mgmt_sk, index, data, len);
+ case MGMT_EV_USER_CONFIRM_REQUEST:
+ return mgmt_user_confirm(mgmt_sk, index, data, len);
+ default:
+ if (monitor)
+ printf("Unhandled event 0x%04x (%s)\n", ev, mgmt_evstr(ev));
+ return 0;
+ }
+}
+
+static int mgmt_process_data(int mgmt_sk)
+{
+ char buf[1024];
+ struct mgmt_hdr *hdr = (void *) buf;
+ uint16_t len, ev, index;
+ ssize_t ret;
+
+ ret = read(mgmt_sk, buf, sizeof(buf));
+ if (ret < 0) {
+ fprintf(stderr, "read: %s\n", strerror(errno));
+ return ret;
+ }
+
+ if (ret < MGMT_HDR_SIZE) {
+ fprintf(stderr, "Too small mgmt packet (%zd bytes)\n", ret);
+ return 0;
+ }
+
+ ev = bt_get_le16(&hdr->opcode);
+ index = bt_get_le16(&hdr->index);
+ len = bt_get_le16(&hdr->len);
+
+ if (monitor)
+ printf("event 0x%04x len 0x%04x index 0x%04x\n", ev, len, index);
+
+ if (ret != MGMT_HDR_SIZE + len) {
+ fprintf(stderr, "Packet length mismatch. ret %zd len %u",
+ ret, len);
+ return 0;
+ }
+
+ mgmt_handle_event(mgmt_sk, ev, index, buf + MGMT_HDR_SIZE, len);
+
+ return 0;
+}
+
+static void cmd_monitor(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ printf("Monitoring mgmt events...\n");
+ monitor = true;
+}
+
+static void version_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ struct mgmt_rp_read_version *rp = rsp;
+
+ if (status != 0) {
+ fprintf(stderr, "Reading mgmt version failed with status"
+ " 0x%02x (%s)\n", status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ if (len < sizeof(*rp)) {
+ fprintf(stderr, "Too small version reply (%u bytes)\n", len);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("MGMT Version %u, revision %u\n", rp->version,
+ bt_get_le16(&rp->revision));
+
+ exit(EXIT_SUCCESS);
+}
+
+static void cmd_version(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE,
+ NULL, 0, version_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send read_version cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void commands_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ struct mgmt_rp_read_commands *rp = rsp;
+ uint16_t num_commands, num_events, *opcode;
+ size_t expected_len;
+ int i;
+
+ if (status != 0) {
+ fprintf(stderr, "Reading supported commands failed with status"
+ " 0x%02x (%s)\n", status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ if (len < sizeof(*rp)) {
+ fprintf(stderr, "Too small commands reply (%u bytes)\n", len);
+ exit(EXIT_FAILURE);
+ }
+
+ num_commands = bt_get_le16(&rp->num_commands);
+ num_events = bt_get_le16(&rp->num_events);
+
+ expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
+ num_events * sizeof(uint16_t);
+
+ if (len < expected_len) {
+ fprintf(stderr, "Too small commands reply (%u != %zu)\n",
+ len, expected_len);
+ exit(EXIT_FAILURE);
+ }
+
+ opcode = rp->opcodes;
+
+ printf("%u commands:\n", num_commands);
+ for (i = 0; i < num_commands; i++) {
+ uint16_t op = bt_get_le16(opcode++);
+ printf("\t%s (0x%04x)\n", mgmt_opstr(op), op);
+ }
+
+ printf("%u events:\n", num_events);
+ for (i = 0; i < num_events; i++) {
+ uint16_t ev = bt_get_le16(opcode++);
+ printf("\t%s (0x%04x)\n", mgmt_evstr(ev), ev);
+ }
+
+ exit(EXIT_SUCCESS);
+}
+
+static void cmd_commands(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE,
+ NULL, 0, commands_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send read_commands cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void info_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ struct mgmt_rp_read_info *rp = rsp;
+ char addr[18];
+
+ if (status != 0) {
+ fprintf(stderr,
+ "Reading hci%u info failed with status 0x%02x (%s)\n",
+ id, status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ if (len < sizeof(*rp)) {
+ fprintf(stderr, "Too small info reply (%u bytes)\n", len);
+ exit(EXIT_FAILURE);
+ }
+
+ ba2str(&rp->bdaddr, addr);
+ printf("hci%u:\taddr %s version %u manufacturer %u"
+ " class 0x%02x%02x%02x\n",
+ id, addr, rp->version, bt_get_le16(&rp->manufacturer),
+ rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+
+ printf("\tsupported settings: ");
+ print_settings(bt_get_le32(&rp->supported_settings));
+
+ printf("\n\tcurrent settings: ");
+ print_settings(bt_get_le32(&rp->current_settings));
+
+ printf("\n\tname %s\n", rp->name);
+ printf("\tshort name %s\n", rp->short_name);
+
+ if (pending == NULL)
+ exit(EXIT_SUCCESS);
+}
+
+static void index_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ struct mgmt_rp_read_index_list *rp = rsp;
+ uint16_t count;
+ unsigned int i;
+
+ if (status != 0) {
+ fprintf(stderr,
+ "Reading index list failed with status 0x%02x (%s)\n",
+ status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ if (len < sizeof(*rp)) {
+ fprintf(stderr, "Too small index list reply (%u bytes)\n",
+ len);
+ exit(EXIT_FAILURE);
+ }
+
+ count = bt_get_le16(&rp->num_controllers);
+
+ if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
+ fprintf(stderr,
+ "Index count (%u) doesn't match reply length (%u)\n",
+ count, len);
+ exit(EXIT_FAILURE);
+ }
+
+ if (monitor)
+ printf("Index list with %u item%s\n",
+ count, count > 1 ? "s" : "");
+
+ if (count == 0)
+ exit(EXIT_SUCCESS);
+
+ if (monitor && count > 0)
+ printf("\t");
+
+ for (i = 0; i < count; i++) {
+ uint16_t index;
+
+ index = bt_get_le16(&rp->index[i]);
+
+ if (monitor)
+ printf("hci%u ", index);
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
+ 0, info_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send read_info cmd\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (monitor && count > 0)
+ printf("\n");
+}
+
+static void cmd_info(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ if (index == MGMT_INDEX_NONE) {
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INDEX_LIST,
+ MGMT_INDEX_NONE, NULL, 0,
+ index_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send index_list cmd\n");
+ exit(EXIT_FAILURE);
+ }
+
+ return;
+ }
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
+ 0, info_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send read_info cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void setting_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ uint32_t *rp = rsp;
+
+ if (status != 0) {
+ fprintf(stderr,
+ "%s for hci%u failed with status 0x%02x (%s)\n",
+ mgmt_opstr(op), id, status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ if (len < sizeof(*rp)) {
+ fprintf(stderr, "Too small %s response (%u bytes)\n",
+ mgmt_opstr(op), len);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("hci%u %s complete, settings: ", id, mgmt_opstr(op));
+ print_settings(bt_get_le32(rp));
+ printf("\n");
+
+ exit(EXIT_SUCCESS);
+}
+
+static void cmd_setting(int mgmt_sk, uint16_t index, uint16_t op,
+ int argc, char **argv)
+{
+ uint8_t val;
+
+ if (argc < 2) {
+ printf("Specify \"on\" or \"off\"\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
+ val = 1;
+ else if (strcasecmp(argv[1], "off") == 0)
+ val = 0;
+ else
+ val = atoi(argv[1]);
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ if (mgmt_send_cmd(mgmt_sk, op, index, &val, sizeof(val),
+ setting_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send %s cmd\n", mgmt_opstr(op));
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void cmd_power(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ cmd_setting(mgmt_sk, index, MGMT_OP_SET_POWERED, argc, argv);
+}
+
+static void cmd_discov(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_set_discoverable cp;
+
+ if (argc < 2) {
+ printf("Usage: btmgmt %s <yes/no> [timeout]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&cp, 0, sizeof(cp));
+
+ if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
+ cp.val = 1;
+ else if (strcasecmp(argv[1], "off") == 0)
+ cp.val = 0;
+ else
+ cp.val = atoi(argv[1]);
+
+ if (argc > 2)
+ cp.timeout = htobs(atoi(argv[2]));
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DISCOVERABLE, index,
+ &cp, sizeof(cp), setting_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send set_discoverable cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void cmd_connectable(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ cmd_setting(mgmt_sk, index, MGMT_OP_SET_CONNECTABLE, argc, argv);
+}
+
+static void cmd_pairable(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ cmd_setting(mgmt_sk, index, MGMT_OP_SET_PAIRABLE, argc, argv);
+}
+
+static void cmd_linksec(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ cmd_setting(mgmt_sk, index, MGMT_OP_SET_LINK_SECURITY, argc, argv);
+}
+
+static void cmd_ssp(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ cmd_setting(mgmt_sk, index, MGMT_OP_SET_SSP, argc, argv);
+}
+
+static void cmd_hs(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ cmd_setting(mgmt_sk, index, MGMT_OP_SET_HS, argc, argv);
+}
+
+static void cmd_le(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ cmd_setting(mgmt_sk, index, MGMT_OP_SET_LE, argc, argv);
+}
+
+static void class_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ struct mgmt_ev_class_of_dev_changed *rp = rsp;
+
+ if (len == 0 && status != 0) {
+ fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+ mgmt_opstr(op), status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ if (len != sizeof(*rp)) {
+ fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("%s succeeded. Class 0x%02x%02x%02x\n", mgmt_opstr(op),
+ rp->class_of_dev[2], rp->class_of_dev[1], rp->class_of_dev[0]);
+
+ exit(EXIT_SUCCESS);
+}
+
+static void cmd_class(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ uint8_t class[2];
+
+ if (argc < 3) {
+ printf("Usage: btmgmt %s <major> <minor>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ class[0] = atoi(argv[1]);
+ class[1] = atoi(argv[2]);
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEV_CLASS, index,
+ class, sizeof(class), class_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send set_dev_class cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void disconnect_rsp(int mgmt_sk, uint16_t op, uint16_t id,
+ uint8_t status, void *rsp, uint16_t len,
+ void *user_data)
+{
+ struct mgmt_rp_disconnect *rp = rsp;
+ char addr[18];
+
+ if (len == 0 && status != 0) {
+ fprintf(stderr, "Disconnect failed with status 0x%02x (%s)\n",
+ status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ if (len != sizeof(*rp)) {
+ fprintf(stderr, "Invalid disconnect response length (%u)\n",
+ len);
+ exit(EXIT_FAILURE);
+ }
+
+ ba2str(&rp->addr.bdaddr, addr);
+
+ if (status == 0) {
+ printf("%s disconnected\n", addr);
+ exit(EXIT_SUCCESS);
+ } else {
+ fprintf(stderr,
+ "Disconnecting %s failed with status 0x%02x (%s)\n",
+ addr, status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void cmd_disconnect(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_disconnect cp;
+
+ if (argc < 2) {
+ printf("Usage: btmgmt %s <address>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ str2ba(argv[1], &cp.addr.bdaddr);
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_DISCONNECT, index,
+ &cp, sizeof(cp), disconnect_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send disconnect cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void con_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ struct mgmt_rp_get_connections *rp = rsp;
+ uint16_t count, i;
+
+ if (len < sizeof(*rp)) {
+ fprintf(stderr, "Too small (%u bytes) get_connections rsp\n",
+ len);
+ exit(EXIT_FAILURE);
+ }
+
+ count = bt_get_le16(&rp->conn_count);
+ if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) {
+ fprintf(stderr, "Invalid get_connections length "
+ " (count=%u, len=%u)\n", count, len);
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < count; i++) {
+ char addr[18];
+
+ ba2str(&rp->addr[i].bdaddr, addr);
+
+ printf("%s type %s\n", addr, typestr(rp->addr[i].type));
+ }
+
+ exit(EXIT_SUCCESS);
+}
+
+static void cmd_con(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_GET_CONNECTIONS, index, NULL, 0,
+ con_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send get_connections cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void find_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ if (status != 0) {
+ fprintf(stderr,
+ "Unable to start discovery. status 0x%02x (%s)\n",
+ status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Discovery started\n");
+ discovery = true;
+}
+
+static void find_usage(void)
+{
+ printf("Usage: btmgmt find [-l|-b]>\n");
+}
+
+static struct option find_options[] = {
+ { "help", 0, 0, 'h' },
+ { "le-only", 1, 0, 'l' },
+ { "bredr-only", 1, 0, 'b' },
+ { 0, 0, 0, 0 }
+};
+
+static void cmd_find(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_start_discovery cp;
+ uint8_t type;
+ int opt;
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ type = 0;
+ hci_set_bit(BDADDR_BREDR, &type);
+ hci_set_bit(BDADDR_LE_PUBLIC, &type);
+ hci_set_bit(BDADDR_LE_RANDOM, &type);
+
+ while ((opt = getopt_long(argc, argv, "+lbh", find_options,
+ NULL)) != -1) {
+ switch (opt) {
+ case 'l':
+ hci_clear_bit(BDADDR_BREDR, &type);
+ hci_set_bit(BDADDR_LE_PUBLIC, &type);
+ hci_set_bit(BDADDR_LE_RANDOM, &type);
+ break;
+ case 'b':
+ hci_set_bit(BDADDR_BREDR, &type);
+ hci_clear_bit(BDADDR_LE_PUBLIC, &type);
+ hci_clear_bit(BDADDR_LE_RANDOM, &type);
+ break;
+ case 'h':
+ default:
+ find_usage();
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.type = type;
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_START_DISCOVERY, index,
+ &cp, sizeof(cp), find_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send start_discovery cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void name_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ if (status != 0) {
+ fprintf(stderr, "Unable to set local name. status 0x%02x (%s)",
+ status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ exit(EXIT_SUCCESS);
+}
+
+static void cmd_name(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_set_local_name cp;
+
+ if (argc < 2) {
+ printf("Usage: btmgmt %s <name> [shortname]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ memset(&cp, 0, sizeof(cp));
+ strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH);
+ if (argc > 2)
+ strncpy((char *) cp.short_name, argv[2],
+ MGMT_MAX_SHORT_NAME_LENGTH);
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_LOCAL_NAME, index,
+ &cp, sizeof(cp), name_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send set_name cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void pair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ struct mgmt_rp_pair_device *rp = rsp;
+ char addr[18];
+
+ if (len == 0 && status != 0) {
+ fprintf(stderr, "Pairing failed with status 0x%02x (%s)\n",
+ status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ if (len != sizeof(*rp)) {
+ fprintf(stderr, "Unexpected pair_rsp len %u\n", len);
+ exit(EXIT_FAILURE);
+ }
+
+ ba2str(&rp->addr.bdaddr, addr);
+
+ if (status != 0) {
+ fprintf(stderr,
+ "Pairing with %s (%s) failed. status 0x%02x (%s)\n",
+ addr, typestr(rp->addr.type), status,
+ mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Paired with %s\n", addr);
+
+ exit(EXIT_SUCCESS);
+}
+
+static void pair_usage(void)
+{
+ printf("Usage: btmgmt pair [-c cap] [-t type] <remote address>\n");
+}
+
+static struct option pair_options[] = {
+ { "help", 0, 0, 'h' },
+ { "capability", 1, 0, 'c' },
+ { "type", 1, 0, 't' },
+ { 0, 0, 0, 0 }
+};
+
+static void cmd_pair(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_pair_device cp;
+ uint8_t cap = 0x01;
+ uint8_t type = BDADDR_BREDR;
+ int opt;
+
+ while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options,
+ NULL)) != -1) {
+ switch (opt) {
+ case 'c':
+ cap = strtol(optarg, NULL, 0);
+ break;
+ case 't':
+ type = strtol(optarg, NULL, 0);
+ break;
+ case 'h':
+ default:
+ pair_usage();
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ pair_usage();
+ exit(EXIT_FAILURE);
+ }
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ memset(&cp, 0, sizeof(cp));
+ str2ba(argv[0], &cp.addr.bdaddr);
+ cp.addr.type = type;
+ cp.io_cap = cap;
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_PAIR_DEVICE, index, &cp, sizeof(cp),
+ pair_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send pair_device cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void unpair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ struct mgmt_rp_unpair_device *rp = rsp;
+ char addr[18];
+
+ if (len == 0 && status != 0) {
+ fprintf(stderr, "Unpair device failed. status 0x%02x (%s)\n",
+ status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ if (len != sizeof(*rp)) {
+ fprintf(stderr, "Unexpected unpair_device_rsp len %u\n", len);
+ exit(EXIT_FAILURE);
+ }
+
+ ba2str(&rp->addr.bdaddr, addr);
+
+ if (status != 0) {
+ fprintf(stderr,
+ "Unpairing %s failed. status 0x%02x (%s)\n",
+ addr, status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("%s unpaired\n", addr);
+
+ exit(EXIT_SUCCESS);
+}
+
+static void cmd_unpair(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_unpair_device cp;
+
+ if (argc < 2) {
+ printf("Usage: btmgmt %s <remote address>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ memset(&cp, 0, sizeof(cp));
+ str2ba(argv[1], &cp.addr.bdaddr);
+ cp.disconnect = 1;
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNPAIR_DEVICE, index, &cp,
+ sizeof(cp), unpair_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send unpair_device cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void keys_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ if (status != 0) {
+ fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n",
+ status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Keys successfully loaded\n");
+
+ exit(EXIT_SUCCESS);
+}
+
+static void cmd_keys(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_load_link_keys cp;
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ memset(&cp, 0, sizeof(cp));
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_LOAD_LINK_KEYS, index,
+ &cp, sizeof(cp), keys_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send load_keys cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void block_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ struct mgmt_addr_info *rp = rsp;
+ char addr[18];
+
+ if (len == 0 && status != 0) {
+ fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+ mgmt_opstr(op), status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ if (len != sizeof(*rp)) {
+ fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
+ exit(EXIT_FAILURE);
+ }
+
+ ba2str(&rp->bdaddr, addr);
+
+ if (status != 0) {
+ fprintf(stderr, "%s %s (%s) failed. status 0x%02x (%s)\n",
+ mgmt_opstr(op), addr, typestr(rp->type),
+ status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("%s %s succeeded\n", mgmt_opstr(op), addr);
+
+ exit(EXIT_SUCCESS);
+}
+
+static void block_usage(void)
+{
+ printf("Usage: btmgmt block [-t type] <remote address>\n");
+}
+
+static struct option block_options[] = {
+ { "help", 0, 0, 'h' },
+ { "type", 1, 0, 't' },
+ { 0, 0, 0, 0 }
+};
+
+static void cmd_block(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_block_device cp;
+ uint8_t type = BDADDR_BREDR;
+ int opt;
+
+ while ((opt = getopt_long(argc, argv, "+t:h", block_options,
+ NULL)) != -1) {
+ switch (opt) {
+ case 't':
+ type = strtol(optarg, NULL, 0);
+ break;
+ case 'h':
+ default:
+ block_usage();
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ block_usage();
+ exit(EXIT_FAILURE);
+ }
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ memset(&cp, 0, sizeof(cp));
+ str2ba(argv[0], &cp.addr.bdaddr);
+ cp.addr.type = type;
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_BLOCK_DEVICE, index,
+ &cp, sizeof(cp), block_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send block_device cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void unblock_usage(void)
+{
+ printf("Usage: btmgmt unblock [-t type] <remote address>\n");
+}
+
+static void cmd_unblock(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_unblock_device cp;
+ uint8_t type = BDADDR_BREDR;
+ int opt;
+
+ while ((opt = getopt_long(argc, argv, "+t:h", block_options,
+ NULL)) != -1) {
+ switch (opt) {
+ case 't':
+ type = strtol(optarg, NULL, 0);
+ break;
+ case 'h':
+ default:
+ unblock_usage();
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ unblock_usage();
+ exit(EXIT_FAILURE);
+ }
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ memset(&cp, 0, sizeof(cp));
+ str2ba(argv[0], &cp.addr.bdaddr);
+ cp.addr.type = type;
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNBLOCK_DEVICE, index,
+ &cp, sizeof(cp), block_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send unblock_device cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
+{
+ if (uuid->type == SDP_UUID16)
+ sdp_uuid16_to_uuid128(uuid128, uuid);
+ else if (uuid->type == SDP_UUID32)
+ sdp_uuid32_to_uuid128(uuid128, uuid);
+ else
+ memcpy(uuid128, uuid, sizeof(*uuid));
+}
+
+static void cmd_add_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_add_uuid cp;
+ uint128_t uint128;
+ uuid_t uuid, uuid128;
+
+ if (argc < 3) {
+ printf("UUID and service hint needed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ if (bt_string2uuid(&uuid, argv[1]) < 0) {
+ printf("Invalid UUID: %s\n", argv[1]);
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&cp, 0, sizeof(cp));
+
+ uuid_to_uuid128(&uuid128, &uuid);
+ ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+ htob128(&uint128, (uint128_t *) cp.uuid);
+
+ cp.svc_hint = atoi(argv[2]);
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_ADD_UUID, index,
+ &cp, sizeof(cp), class_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send add_uuid cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void cmd_remove_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_remove_uuid cp;
+ uint128_t uint128;
+ uuid_t uuid, uuid128;
+
+ if (argc < 2) {
+ printf("UUID needed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ if (bt_string2uuid(&uuid, argv[1]) < 0) {
+ printf("Invalid UUID: %s\n", argv[1]);
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&cp, 0, sizeof(cp));
+
+ uuid_to_uuid128(&uuid128, &uuid);
+ ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+ htob128(&uint128, (uint128_t *) cp.uuid);
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_REMOVE_UUID, index,
+ &cp, sizeof(cp), class_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send remove_uuid cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void cmd_clr_uuids(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ char *uuid_any = "00000000-0000-0000-0000-000000000000";
+ char *rm_argv[] = { "rm-uuid", uuid_any, NULL };
+
+ cmd_remove_uuid(mgmt_sk, index, 2, rm_argv);
+}
+
+static void did_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+ void *rsp, uint16_t len, void *user_data)
+{
+ if (status != 0) {
+ fprintf(stderr, "Set Device ID failed with status 0x%02x (%s)\n",
+ status, mgmt_errstr(status));
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Device ID successfully set\n");
+
+ exit(EXIT_SUCCESS);
+}
+
+static void did_usage(void)
+{
+ printf("Usage: btmgmt did <source>:<vendor>:<product>:<version>\n");
+ printf(" possible source values: bluetooth, usb\n");
+}
+
+static void cmd_did(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+ struct mgmt_cp_set_device_id cp;
+ uint16_t vendor, product, version , source;
+ int result;
+
+ if (argc < 2) {
+ did_usage();
+ exit(EXIT_FAILURE);
+ }
+
+ result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product,
+ &version);
+ if (result == 3) {
+ source = 0x0001;
+ goto done;
+ }
+
+ result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product,
+ &version);
+ if (result == 3) {
+ source = 0x0002;
+ goto done;
+ }
+
+ did_usage();
+ exit(EXIT_FAILURE);
+
+done:
+ if (index == MGMT_INDEX_NONE)
+ index = 0;
+
+ cp.source = htobs(source);
+ cp.vendor = htobs(vendor);
+ cp.product = htobs(product);
+ cp.version = htobs(version);
+
+ if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEVICE_ID, index,
+ &cp, sizeof(cp), did_rsp, NULL) < 0) {
+ fprintf(stderr, "Unable to send set_dev_class cmd\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+static struct {
+ char *cmd;
+ void (*func)(int mgmt_sk, uint16_t index, int argc, char **argv);
+ char *doc;
+} command[] = {
+ { "monitor", cmd_monitor, "Monitor events" },
+ { "version", cmd_version, "Get the MGMT Version" },
+ { "commands", cmd_commands, "List supported commands" },
+ { "info", cmd_info, "Show controller info" },
+ { "power", cmd_power, "Toggle powered state" },
+ { "discov", cmd_discov, "Toggle discoverable state" },
+ { "connectable",cmd_connectable,"Toggle connectable state" },
+ { "pairable", cmd_pairable, "Toggle pairable state" },
+ { "linksec", cmd_linksec, "Toggle link level security" },
+ { "ssp", cmd_ssp, "Toggle SSP mode" },
+ { "hs", cmd_hs, "Toggle HS Support" },
+ { "le", cmd_le, "Toggle LE Support" },
+ { "class", cmd_class, "Set device major/minor class" },
+ { "disconnect", cmd_disconnect, "Disconnect device" },
+ { "con", cmd_con, "List connections" },
+ { "find", cmd_find, "Discover nearby devices" },
+ { "name", cmd_name, "Set local name" },
+ { "pair", cmd_pair, "Pair with a remote device" },
+ { "unpair", cmd_unpair, "Unpair device" },
+ { "keys", cmd_keys, "Load Keys" },
+ { "block", cmd_block, "Block Device" },
+ { "unblock", cmd_unblock, "Unblock Device" },
+ { "add-uuid", cmd_add_uuid, "Add UUID" },
+ { "rm-uuid", cmd_add_uuid, "Remove UUID" },
+ { "clr-uuids", cmd_clr_uuids, "Clear UUIDs", },
+ { "did", cmd_did, "Set Device ID", },
+ { NULL, NULL, 0 }
+};
+
+static void usage(void)
+{
+ int i;
+
+ printf("btmgmt ver %s\n", VERSION);
+ printf("Usage:\n"
+ "\tbtmgmt [options] <command> [command parameters]\n");
+
+ printf("Options:\n"
+ "\t--index <id>\tSpecify adapter index\n"
+ "\t--verbose\tEnable extra logging\n"
+ "\t--help\tDisplay help\n");
+
+ printf("Commands:\n");
+ for (i = 0; command[i].cmd; i++)
+ printf("\t%-15s\t%s\n", command[i].cmd, command[i].doc);
+
+ printf("\n"
+ "For more information on the usage of each command use:\n"
+ "\tbtmgmt <command> --help\n" );
+}
+
+static struct option main_options[] = {
+ { "index", 1, 0, 'i' },
+ { "verbose", 0, 0, 'v' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ int opt, i, mgmt_sk;
+ uint16_t index = MGMT_INDEX_NONE;
+ struct pollfd pollfd;
+
+ while ((opt = getopt_long(argc, argv, "+hvi:",
+ main_options, NULL)) != -1) {
+ switch (opt) {
+ case 'i':
+ if (strlen(optarg) > 3 &&
+ strncasecmp(optarg, "hci", 3) == 0)
+ index = atoi(&optarg[4]);
+ else
+ index = atoi(optarg);
+ break;
+ case 'v':
+ monitor = true;
+ break;
+ case 'h':
+ default:
+ usage();
+ return 0;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < 1) {
+ usage();
+ return 0;
+ }
+
+ mgmt_sk = mgmt_open();
+ if (mgmt_sk < 0) {
+ fprintf(stderr, "Unable to open mgmt socket\n");
+ return -1;
+ }
+
+ for (i = 0; command[i].cmd; i++) {
+ if (strcmp(command[i].cmd, argv[0]) != 0)
+ continue;
+
+ command[i].func(mgmt_sk, index, argc, argv);
+ break;
+ }
+
+ if (command[i].cmd == NULL) {
+ fprintf(stderr, "Unknown command: %s\n", argv[0]);
+ close(mgmt_sk);
+ return -1;
+ }
+
+ pollfd.fd = mgmt_sk;
+ pollfd.events = POLLIN;
+ pollfd.revents = 0;
+
+ while (poll(&pollfd, 1, -1) >= 0) {
+ if (pollfd.revents & (POLLHUP | POLLERR | POLLNVAL))
+ break;
+
+ if (pollfd.revents & POLLIN)
+ mgmt_process_data(mgmt_sk);
+
+ pollfd.revents = 0;
+ }
+
+ close(mgmt_sk);
+
+ return 0;
+}
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 17/21] alert: move alert to profiles dir
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (14 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 16/21] btmgmt: move to " Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 18/21] deviceinfo: move to profiles folder Gustavo Padovan
` (3 subsequent siblings)
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
Makefile.am | 3 ++-
alert/main.c | 58 -----------------------------------------------
alert/server.c | 38 -------------------------------
alert/server.h | 26 ---------------------
profiles/alert/main.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++
profiles/alert/server.c | 38 +++++++++++++++++++++++++++++++
profiles/alert/server.h | 26 +++++++++++++++++++++
7 files changed, 124 insertions(+), 123 deletions(-)
delete mode 100644 alert/main.c
delete mode 100644 alert/server.c
delete mode 100644 alert/server.h
create mode 100644 profiles/alert/main.c
create mode 100644 profiles/alert/server.c
create mode 100644 profiles/alert/server.h
diff --git a/Makefile.am b/Makefile.am
index 6dc1415..b8f3bbb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -223,7 +223,8 @@ builtin_modules += thermometer alert time gatt_example proximity \
builtin_sources += thermometer/main.c \
thermometer/manager.h thermometer/manager.c \
thermometer/thermometer.h thermometer/thermometer.c \
- alert/main.c alert/server.h alert/server.c \
+ profiles/alert/main.c profiles/alert/server.h \
+ profiles/alert/server.c \
time/main.c time/server.h time/server.c \
plugins/gatt-example.c \
proximity/main.c proximity/manager.h proximity/manager.c \
diff --git a/alert/main.c b/alert/main.c
deleted file mode 100644
index ec4ab6d..0000000
--- a/alert/main.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 Nokia Corporation
- * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 <stdint.h>
-#include <glib.h>
-#include <errno.h>
-
-#include "plugin.h"
-#include "hcid.h"
-#include "log.h"
-#include "server.h"
-
-static int alert_init(void)
-{
- if (!main_opts.gatt_enabled) {
- DBG("GATT is disabled");
- return -ENOTSUP;
- }
-
- return alert_server_init();
-}
-
-static void alert_exit(void)
-{
- if (!main_opts.gatt_enabled)
- return;
-
- alert_server_exit();
-}
-
-BLUETOOTH_PLUGIN_DEFINE(alert, VERSION,
- BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
- alert_init, alert_exit)
diff --git a/alert/server.c b/alert/server.c
deleted file mode 100644
index d91b156..0000000
--- a/alert/server.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 Nokia Corporation
- * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 "server.h"
-
-int alert_server_init(void)
-{
- return 0;
-}
-
-void alert_server_exit(void)
-{
-}
diff --git a/alert/server.h b/alert/server.h
deleted file mode 100644
index e59bdb1..0000000
--- a/alert/server.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 Nokia Corporation
- * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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
- *
- */
-
-int alert_server_init(void);
-void alert_server_exit(void);
diff --git a/profiles/alert/main.c b/profiles/alert/main.c
new file mode 100644
index 0000000..ec4ab6d
--- /dev/null
+++ b/profiles/alert/main.c
@@ -0,0 +1,58 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 <stdint.h>
+#include <glib.h>
+#include <errno.h>
+
+#include "plugin.h"
+#include "hcid.h"
+#include "log.h"
+#include "server.h"
+
+static int alert_init(void)
+{
+ if (!main_opts.gatt_enabled) {
+ DBG("GATT is disabled");
+ return -ENOTSUP;
+ }
+
+ return alert_server_init();
+}
+
+static void alert_exit(void)
+{
+ if (!main_opts.gatt_enabled)
+ return;
+
+ alert_server_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(alert, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+ alert_init, alert_exit)
diff --git a/profiles/alert/server.c b/profiles/alert/server.c
new file mode 100644
index 0000000..d91b156
--- /dev/null
+++ b/profiles/alert/server.c
@@ -0,0 +1,38 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 "server.h"
+
+int alert_server_init(void)
+{
+ return 0;
+}
+
+void alert_server_exit(void)
+{
+}
diff --git a/profiles/alert/server.h b/profiles/alert/server.h
new file mode 100644
index 0000000..e59bdb1
--- /dev/null
+++ b/profiles/alert/server.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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
+ *
+ */
+
+int alert_server_init(void);
+void alert_server_exit(void);
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 18/21] deviceinfo: move to profiles folder
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (15 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 17/21] alert: move alert to profiles dir Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-14 13:49 ` [PATCH 19/21] proximity: move to the " Gustavo Padovan
2012-06-13 20:43 ` [PATCH 20/21] thermometer: " Gustavo Padovan
` (2 subsequent siblings)
19 siblings, 1 reply; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
Makefile.am | 11 ++-
deviceinfo/deviceinfo.c | 192 --------------------------------------
deviceinfo/deviceinfo.h | 24 -----
deviceinfo/main.c | 52 -----------
deviceinfo/manager.c | 80 ----------------
deviceinfo/manager.h | 24 -----
profiles/deviceinfo/deviceinfo.c | 192 ++++++++++++++++++++++++++++++++++++++
profiles/deviceinfo/deviceinfo.h | 24 +++++
profiles/deviceinfo/main.c | 52 +++++++++++
profiles/deviceinfo/manager.c | 80 ++++++++++++++++
profiles/deviceinfo/manager.h | 24 +++++
11 files changed, 378 insertions(+), 377 deletions(-)
delete mode 100644 deviceinfo/deviceinfo.c
delete mode 100644 deviceinfo/deviceinfo.h
delete mode 100644 deviceinfo/main.c
delete mode 100644 deviceinfo/manager.c
delete mode 100644 deviceinfo/manager.h
create mode 100644 profiles/deviceinfo/deviceinfo.c
create mode 100644 profiles/deviceinfo/deviceinfo.h
create mode 100644 profiles/deviceinfo/main.c
create mode 100644 profiles/deviceinfo/manager.c
create mode 100644 profiles/deviceinfo/manager.h
diff --git a/Makefile.am b/Makefile.am
index b8f3bbb..c239433 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -218,8 +218,7 @@ builtin_sources += health/hdp_main.c health/hdp_types.h \
endif
if GATTMODULES
-builtin_modules += thermometer alert time gatt_example proximity \
- deviceinfo
+builtin_modules += thermometer alert time gatt_example proximity deviceinfo
builtin_sources += thermometer/main.c \
thermometer/manager.h thermometer/manager.c \
thermometer/thermometer.h thermometer/thermometer.c \
@@ -232,9 +231,11 @@ builtin_sources += thermometer/main.c \
proximity/reporter.h proximity/reporter.c \
proximity/linkloss.h proximity/linkloss.c \
proximity/immalert.h proximity/immalert.c \
- deviceinfo/main.c \
- deviceinfo/manager.h deviceinfo/manager.c \
- deviceinfo/deviceinfo.h deviceinfo/deviceinfo.c
+ profiles/deviceinfo/main.c \
+ profiles/deviceinfo/manager.h \
+ profiles/deviceinfo/manager.c \
+ profiles/deviceinfo/deviceinfo.h \
+ profiles/deviceinfo/deviceinfo.c
endif
diff --git a/deviceinfo/deviceinfo.c b/deviceinfo/deviceinfo.c
deleted file mode 100644
index 8c3af93..0000000
--- a/deviceinfo/deviceinfo.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2012 Texas Instruments, 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 <glib.h>
-#include <bluetooth/uuid.h>
-
-#include "adapter.h"
-#include "device.h"
-#include "gattrib.h"
-#include "attio.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "log.h"
-#include "deviceinfo.h"
-
-struct deviceinfo {
- struct btd_device *dev; /* Device reference */
- GAttrib *attrib; /* GATT connection */
- guint attioid; /* Att watcher id */
- struct att_range *svc_range; /* DeviceInfo range */
- GSList *chars; /* Characteristics */
-};
-
-static GSList *servers = NULL;
-
-struct characteristic {
- struct gatt_char attr; /* Characteristic */
- struct deviceinfo *d; /* deviceinfo where the char belongs */
-};
-
-static void deviceinfo_free(gpointer user_data)
-{
- struct deviceinfo *d = user_data;
-
- if (d->attioid > 0)
- btd_device_remove_attio_callback(d->dev, d->attioid);
-
- if (d->attrib != NULL)
- g_attrib_unref(d->attrib);
-
- g_slist_free_full(d->chars, g_free);
-
- btd_device_unref(d->dev);
- g_free(d->svc_range);
- g_free(d);
-}
-
-static gint cmp_device(gconstpointer a, gconstpointer b)
-{
- const struct deviceinfo *d = a;
- const struct btd_device *dev = b;
-
- if (dev == d->dev)
- return 0;
-
- return -1;
-}
-
-static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
-{
- struct characteristic *ch = user_data;
- uint8_t value[ATT_MAX_MTU];
- int vlen;
-
- if (status != 0) {
- error("Error reading PNP_ID value: %s", att_ecode2str(status));
- return;
- }
-
- if (!dec_read_resp(pdu, len, value, &vlen)) {
- error("Error reading PNP_ID: Protocol error");
- return;
- }
-
- if (vlen < 7) {
- error("Error reading PNP_ID: Invalid pdu length received");
- return;
- }
-
- device_set_pnpid(ch->d->dev, value[0], att_get_u16(&value[1]),
- att_get_u16(&value[3]), att_get_u16(&value[5]));
-}
-
-static void process_deviceinfo_char(struct characteristic *ch)
-{
- if (g_strcmp0(ch->attr.uuid, PNPID_UUID) == 0)
- gatt_read_char(ch->d->attrib, ch->attr.value_handle, 0,
- read_pnpid_cb, ch);
-}
-
-static void configure_deviceinfo_cb(GSList *characteristics, guint8 status,
- gpointer user_data)
-{
- struct deviceinfo *d = user_data;
- GSList *l;
-
- if (status != 0) {
- error("Discover deviceinfo characteristics: %s",
- att_ecode2str(status));
- return;
- }
-
- for (l = characteristics; l; l = l->next) {
- struct gatt_char *c = l->data;
- struct characteristic *ch;
-
- ch = g_new0(struct characteristic, 1);
- ch->attr.handle = c->handle;
- ch->attr.properties = c->properties;
- ch->attr.value_handle = c->value_handle;
- memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
- ch->d = d;
-
- d->chars = g_slist_append(d->chars, ch);
-
- process_deviceinfo_char(ch);
- }
-}
-static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-{
- struct deviceinfo *d = user_data;
-
- d->attrib = g_attrib_ref(attrib);
-
- gatt_discover_char(d->attrib, d->svc_range->start, d->svc_range->end,
- NULL, configure_deviceinfo_cb, d);
-}
-
-static void attio_disconnected_cb(gpointer user_data)
-{
- struct deviceinfo *d = user_data;
-
- g_attrib_unref(d->attrib);
- d->attrib = NULL;
-}
-
-int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim)
-{
- struct deviceinfo *d;
-
- d = g_new0(struct deviceinfo, 1);
- d->dev = btd_device_ref(device);
- d->svc_range = g_new0(struct att_range, 1);
- d->svc_range->start = prim->range.start;
- d->svc_range->end = prim->range.end;
-
- servers = g_slist_prepend(servers, d);
-
- d->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
- attio_disconnected_cb, d);
- return 0;
-}
-
-void deviceinfo_unregister(struct btd_device *device)
-{
- struct deviceinfo *d;
- GSList *l;
-
- l = g_slist_find_custom(servers, device, cmp_device);
- if (l == NULL)
- return;
-
- d = l->data;
- servers = g_slist_remove(servers, d);
-
- deviceinfo_free(d);
-}
diff --git a/deviceinfo/deviceinfo.h b/deviceinfo/deviceinfo.h
deleted file mode 100644
index 7a804a5..0000000
--- a/deviceinfo/deviceinfo.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2012 Texas Instruments, 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
- *
- */
-
-int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim);
-void deviceinfo_unregister(struct btd_device *device);
diff --git a/deviceinfo/main.c b/deviceinfo/main.c
deleted file mode 100644
index 82ecc82..0000000
--- a/deviceinfo/main.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2012 Texas Instruments, 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 <glib.h>
-#include <errno.h>
-#include <stdint.h>
-
-#include "plugin.h"
-#include "manager.h"
-#include "hcid.h"
-#include "log.h"
-
-static int deviceinfo_init(void)
-{
- if (!main_opts.gatt_enabled) {
- error("DIS cannot start: GATT is disabled");
- return -ENOTSUP;
- }
-
- return deviceinfo_manager_init();
-}
-
-static void deviceinfo_exit(void)
-{
- deviceinfo_manager_exit();
-}
-
-BLUETOOTH_PLUGIN_DEFINE(deviceinfo, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
- deviceinfo_init, deviceinfo_exit)
diff --git a/deviceinfo/manager.c b/deviceinfo/manager.c
deleted file mode 100644
index 1d59918..0000000
--- a/deviceinfo/manager.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2012 Texas Instruments, 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
- *
- */
-
-#include <glib.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-
-#include "adapter.h"
-#include "device.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "deviceinfo.h"
-#include "manager.h"
-
-static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
-{
- const struct gatt_primary *prim = a;
- const char *uuid = b;
-
- return g_strcmp0(prim->uuid, uuid);
-}
-
-static int deviceinfo_driver_probe(struct btd_device *device, GSList *uuids)
-{
- struct gatt_primary *prim;
- GSList *primaries, *l;
-
- primaries = btd_device_get_primaries(device);
-
- l = g_slist_find_custom(primaries, DEVICE_INFORMATION_UUID,
- primary_uuid_cmp);
- if (l == NULL)
- return -EINVAL;
-
- prim = l->data;
-
- return deviceinfo_register(device, prim);
-}
-
-static void deviceinfo_driver_remove(struct btd_device *device)
-{
- deviceinfo_unregister(device);
-}
-
-static struct btd_device_driver deviceinfo_device_driver = {
- .name = "deviceinfo-driver",
- .uuids = BTD_UUIDS(DEVICE_INFORMATION_UUID),
- .probe = deviceinfo_driver_probe,
- .remove = deviceinfo_driver_remove
-};
-
-int deviceinfo_manager_init(void)
-{
- return btd_register_device_driver(&deviceinfo_device_driver);
-}
-
-void deviceinfo_manager_exit(void)
-{
- btd_unregister_device_driver(&deviceinfo_device_driver);
-}
diff --git a/deviceinfo/manager.h b/deviceinfo/manager.h
deleted file mode 100644
index 0f742ca..0000000
--- a/deviceinfo/manager.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2012 Texas Instruments, 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
- *
- */
-
-int deviceinfo_manager_init(void);
-void deviceinfo_manager_exit(void);
diff --git a/profiles/deviceinfo/deviceinfo.c b/profiles/deviceinfo/deviceinfo.c
new file mode 100644
index 0000000..8c3af93
--- /dev/null
+++ b/profiles/deviceinfo/deviceinfo.c
@@ -0,0 +1,192 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, 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 <glib.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "gattrib.h"
+#include "attio.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "log.h"
+#include "deviceinfo.h"
+
+struct deviceinfo {
+ struct btd_device *dev; /* Device reference */
+ GAttrib *attrib; /* GATT connection */
+ guint attioid; /* Att watcher id */
+ struct att_range *svc_range; /* DeviceInfo range */
+ GSList *chars; /* Characteristics */
+};
+
+static GSList *servers = NULL;
+
+struct characteristic {
+ struct gatt_char attr; /* Characteristic */
+ struct deviceinfo *d; /* deviceinfo where the char belongs */
+};
+
+static void deviceinfo_free(gpointer user_data)
+{
+ struct deviceinfo *d = user_data;
+
+ if (d->attioid > 0)
+ btd_device_remove_attio_callback(d->dev, d->attioid);
+
+ if (d->attrib != NULL)
+ g_attrib_unref(d->attrib);
+
+ g_slist_free_full(d->chars, g_free);
+
+ btd_device_unref(d->dev);
+ g_free(d->svc_range);
+ g_free(d);
+}
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+ const struct deviceinfo *d = a;
+ const struct btd_device *dev = b;
+
+ if (dev == d->dev)
+ return 0;
+
+ return -1;
+}
+
+static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct characteristic *ch = user_data;
+ uint8_t value[ATT_MAX_MTU];
+ int vlen;
+
+ if (status != 0) {
+ error("Error reading PNP_ID value: %s", att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_read_resp(pdu, len, value, &vlen)) {
+ error("Error reading PNP_ID: Protocol error");
+ return;
+ }
+
+ if (vlen < 7) {
+ error("Error reading PNP_ID: Invalid pdu length received");
+ return;
+ }
+
+ device_set_pnpid(ch->d->dev, value[0], att_get_u16(&value[1]),
+ att_get_u16(&value[3]), att_get_u16(&value[5]));
+}
+
+static void process_deviceinfo_char(struct characteristic *ch)
+{
+ if (g_strcmp0(ch->attr.uuid, PNPID_UUID) == 0)
+ gatt_read_char(ch->d->attrib, ch->attr.value_handle, 0,
+ read_pnpid_cb, ch);
+}
+
+static void configure_deviceinfo_cb(GSList *characteristics, guint8 status,
+ gpointer user_data)
+{
+ struct deviceinfo *d = user_data;
+ GSList *l;
+
+ if (status != 0) {
+ error("Discover deviceinfo characteristics: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ for (l = characteristics; l; l = l->next) {
+ struct gatt_char *c = l->data;
+ struct characteristic *ch;
+
+ ch = g_new0(struct characteristic, 1);
+ ch->attr.handle = c->handle;
+ ch->attr.properties = c->properties;
+ ch->attr.value_handle = c->value_handle;
+ memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+ ch->d = d;
+
+ d->chars = g_slist_append(d->chars, ch);
+
+ process_deviceinfo_char(ch);
+ }
+}
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+ struct deviceinfo *d = user_data;
+
+ d->attrib = g_attrib_ref(attrib);
+
+ gatt_discover_char(d->attrib, d->svc_range->start, d->svc_range->end,
+ NULL, configure_deviceinfo_cb, d);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+ struct deviceinfo *d = user_data;
+
+ g_attrib_unref(d->attrib);
+ d->attrib = NULL;
+}
+
+int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim)
+{
+ struct deviceinfo *d;
+
+ d = g_new0(struct deviceinfo, 1);
+ d->dev = btd_device_ref(device);
+ d->svc_range = g_new0(struct att_range, 1);
+ d->svc_range->start = prim->range.start;
+ d->svc_range->end = prim->range.end;
+
+ servers = g_slist_prepend(servers, d);
+
+ d->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
+ attio_disconnected_cb, d);
+ return 0;
+}
+
+void deviceinfo_unregister(struct btd_device *device)
+{
+ struct deviceinfo *d;
+ GSList *l;
+
+ l = g_slist_find_custom(servers, device, cmp_device);
+ if (l == NULL)
+ return;
+
+ d = l->data;
+ servers = g_slist_remove(servers, d);
+
+ deviceinfo_free(d);
+}
diff --git a/profiles/deviceinfo/deviceinfo.h b/profiles/deviceinfo/deviceinfo.h
new file mode 100644
index 0000000..7a804a5
--- /dev/null
+++ b/profiles/deviceinfo/deviceinfo.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, 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
+ *
+ */
+
+int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim);
+void deviceinfo_unregister(struct btd_device *device);
diff --git a/profiles/deviceinfo/main.c b/profiles/deviceinfo/main.c
new file mode 100644
index 0000000..82ecc82
--- /dev/null
+++ b/profiles/deviceinfo/main.c
@@ -0,0 +1,52 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, 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 <glib.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include "plugin.h"
+#include "manager.h"
+#include "hcid.h"
+#include "log.h"
+
+static int deviceinfo_init(void)
+{
+ if (!main_opts.gatt_enabled) {
+ error("DIS cannot start: GATT is disabled");
+ return -ENOTSUP;
+ }
+
+ return deviceinfo_manager_init();
+}
+
+static void deviceinfo_exit(void)
+{
+ deviceinfo_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(deviceinfo, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+ deviceinfo_init, deviceinfo_exit)
diff --git a/profiles/deviceinfo/manager.c b/profiles/deviceinfo/manager.c
new file mode 100644
index 0000000..1d59918
--- /dev/null
+++ b/profiles/deviceinfo/manager.c
@@ -0,0 +1,80 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, 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
+ *
+ */
+
+#include <glib.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "deviceinfo.h"
+#include "manager.h"
+
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_primary *prim = a;
+ const char *uuid = b;
+
+ return g_strcmp0(prim->uuid, uuid);
+}
+
+static int deviceinfo_driver_probe(struct btd_device *device, GSList *uuids)
+{
+ struct gatt_primary *prim;
+ GSList *primaries, *l;
+
+ primaries = btd_device_get_primaries(device);
+
+ l = g_slist_find_custom(primaries, DEVICE_INFORMATION_UUID,
+ primary_uuid_cmp);
+ if (l == NULL)
+ return -EINVAL;
+
+ prim = l->data;
+
+ return deviceinfo_register(device, prim);
+}
+
+static void deviceinfo_driver_remove(struct btd_device *device)
+{
+ deviceinfo_unregister(device);
+}
+
+static struct btd_device_driver deviceinfo_device_driver = {
+ .name = "deviceinfo-driver",
+ .uuids = BTD_UUIDS(DEVICE_INFORMATION_UUID),
+ .probe = deviceinfo_driver_probe,
+ .remove = deviceinfo_driver_remove
+};
+
+int deviceinfo_manager_init(void)
+{
+ return btd_register_device_driver(&deviceinfo_device_driver);
+}
+
+void deviceinfo_manager_exit(void)
+{
+ btd_unregister_device_driver(&deviceinfo_device_driver);
+}
diff --git a/profiles/deviceinfo/manager.h b/profiles/deviceinfo/manager.h
new file mode 100644
index 0000000..0f742ca
--- /dev/null
+++ b/profiles/deviceinfo/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, 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
+ *
+ */
+
+int deviceinfo_manager_init(void);
+void deviceinfo_manager_exit(void);
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 20/21] thermometer: move to the profiles folder
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (16 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 18/21] deviceinfo: move to profiles folder Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-13 20:43 ` [PATCH 21/21] time: " Gustavo Padovan
2012-06-14 9:22 ` [PATCH 00/21] BlueZ 5.0 patches Bastien Nocera
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
Makefile.am | 8 +-
profiles/thermometer/main.c | 70 ++
profiles/thermometer/manager.c | 92 +++
profiles/thermometer/manager.h | 24 +
profiles/thermometer/thermometer.c | 1265 ++++++++++++++++++++++++++++++++++++
profiles/thermometer/thermometer.h | 25 +
thermometer/main.c | 70 --
thermometer/manager.c | 92 ---
thermometer/manager.h | 24 -
thermometer/thermometer.c | 1265 ------------------------------------
thermometer/thermometer.h | 25 -
11 files changed, 1481 insertions(+), 1479 deletions(-)
create mode 100644 profiles/thermometer/main.c
create mode 100644 profiles/thermometer/manager.c
create mode 100644 profiles/thermometer/manager.h
create mode 100644 profiles/thermometer/thermometer.c
create mode 100644 profiles/thermometer/thermometer.h
delete mode 100644 thermometer/main.c
delete mode 100644 thermometer/manager.c
delete mode 100644 thermometer/manager.h
delete mode 100644 thermometer/thermometer.c
delete mode 100644 thermometer/thermometer.h
diff --git a/Makefile.am b/Makefile.am
index 86c440d..631af43 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -219,9 +219,11 @@ endif
if GATTMODULES
builtin_modules += thermometer alert time gatt_example proximity deviceinfo
-builtin_sources += thermometer/main.c \
- thermometer/manager.h thermometer/manager.c \
- thermometer/thermometer.h thermometer/thermometer.c \
+builtin_sources += profiles/thermometer/main.c \
+ profiles/thermometer/manager.h \
+ profiles/thermometer/manager.c \
+ profiles/thermometer/thermometer.h \
+ profiles/thermometer/thermometer.c \
profiles/alert/main.c profiles/alert/server.h \
profiles/alert/server.c \
time/main.c time/server.h time/server.c \
diff --git a/profiles/thermometer/main.c b/profiles/thermometer/main.c
new file mode 100644
index 0000000..4447b52
--- /dev/null
+++ b/profiles/thermometer/main.c
@@ -0,0 +1,70 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * 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 <stdint.h>
+#include <glib.h>
+#include <errno.h>
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "manager.h"
+#include "hcid.h"
+#include "log.h"
+
+static DBusConnection *connection = NULL;
+
+static int thermometer_init(void)
+{
+ if (!main_opts.gatt_enabled) {
+ DBG("GATT is disabled");
+ return -ENOTSUP;
+ }
+
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (connection == NULL)
+ return -EIO;
+
+ if (thermometer_manager_init(connection) < 0) {
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void thermometer_exit(void)
+{
+ if (!main_opts.gatt_enabled)
+ return;
+
+ thermometer_manager_exit();
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
+
+BLUETOOTH_PLUGIN_DEFINE(thermometer, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+ thermometer_init, thermometer_exit)
diff --git a/profiles/thermometer/manager.c b/profiles/thermometer/manager.c
new file mode 100644
index 0000000..3d5452b
--- /dev/null
+++ b/profiles/thermometer/manager.c
@@ -0,0 +1,92 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * 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
+ *
+ */
+
+#include <gdbus.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "thermometer.h"
+#include "manager.h"
+
+static DBusConnection *connection = NULL;
+
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_primary *prim = a;
+ const char *uuid = b;
+
+ return g_strcmp0(prim->uuid, uuid);
+}
+
+static int thermometer_driver_probe(struct btd_device *device, GSList *uuids)
+{
+ struct gatt_primary *tattr;
+ GSList *primaries, *l;
+
+ primaries = btd_device_get_primaries(device);
+
+ l = g_slist_find_custom(primaries, HEALTH_THERMOMETER_UUID,
+ primary_uuid_cmp);
+ if (l == NULL)
+ return -EINVAL;
+
+ tattr = l->data;
+
+ return thermometer_register(connection, device, tattr);
+}
+
+static void thermometer_driver_remove(struct btd_device *device)
+{
+ thermometer_unregister(device);
+}
+
+static struct btd_device_driver thermometer_device_driver = {
+ .name = "thermometer-device-driver",
+ .uuids = BTD_UUIDS(HEALTH_THERMOMETER_UUID),
+ .probe = thermometer_driver_probe,
+ .remove = thermometer_driver_remove
+};
+
+int thermometer_manager_init(DBusConnection *conn)
+{
+ int ret;
+
+ ret = btd_register_device_driver(&thermometer_device_driver);
+ if (ret < 0)
+ return ret;
+
+ connection = dbus_connection_ref(conn);
+ return 0;
+}
+
+void thermometer_manager_exit(void)
+{
+ btd_unregister_device_driver(&thermometer_device_driver);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
diff --git a/profiles/thermometer/manager.h b/profiles/thermometer/manager.h
new file mode 100644
index 0000000..ed928ad
--- /dev/null
+++ b/profiles/thermometer/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * 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
+ *
+ */
+
+int thermometer_manager_init(DBusConnection *conn);
+void thermometer_manager_exit(void);
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
new file mode 100644
index 0000000..85f0811
--- /dev/null
+++ b/profiles/thermometer/thermometer.c
@@ -0,0 +1,1265 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * 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 <gdbus.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "dbus-common.h"
+#include "adapter.h"
+#include "device.h"
+#include "error.h"
+#include "log.h"
+#include "gattrib.h"
+#include "attio.h"
+#include "att.h"
+#include "gatt.h"
+#include "thermometer.h"
+
+#define THERMOMETER_INTERFACE "org.bluez.Thermometer"
+
+/* Temperature measurement flag fields */
+#define TEMP_UNITS 0x01
+#define TEMP_TIME_STAMP 0x02
+#define TEMP_TYPE 0x04
+
+#define FLOAT_MAX_MANTISSA 16777216 /* 2^24 */
+
+struct thermometer {
+ DBusConnection *conn; /* The connection to the bus */
+ struct btd_device *dev; /* Device reference */
+ GAttrib *attrib; /* GATT connection */
+ struct att_range *svc_range; /* Thermometer range */
+ guint attioid; /* Att watcher id */
+ guint attindid; /* Att incications id */
+ guint attnotid; /* Att notifications id */
+ GSList *chars; /* Characteristics */
+ GSList *fwatchers; /* Final measurements */
+ GSList *iwatchers; /* Intermediate measurements */
+ gboolean intermediate;
+ uint8_t type;
+ uint16_t interval;
+ uint16_t max;
+ uint16_t min;
+ gboolean has_type;
+ gboolean has_interval;
+};
+
+struct characteristic {
+ struct gatt_char attr; /* Characteristic */
+ GSList *desc; /* Descriptors */
+ struct thermometer *t; /* Thermometer where the char belongs */
+};
+
+struct descriptor {
+ struct characteristic *ch;
+ uint16_t handle;
+ bt_uuid_t uuid;
+};
+
+struct watcher {
+ struct thermometer *t;
+ guint id;
+ char *srv;
+ char *path;
+};
+
+struct measurement {
+ int16_t exp;
+ int32_t mant;
+ uint64_t time;
+ gboolean suptime;
+ char *unit;
+ char *type;
+ char *value;
+};
+
+struct tmp_interval_data {
+ struct thermometer *thermometer;
+ uint16_t interval;
+};
+
+static GSList *thermometers = NULL;
+
+const char *temp_type[] = {
+ "<reserved>",
+ "Armpit",
+ "Body",
+ "Ear",
+ "Finger",
+ "Intestines",
+ "Mouth",
+ "Rectum",
+ "Toe",
+ "Tympanum"
+};
+
+static const gchar *temptype2str(uint8_t value)
+{
+ if (value > 0 && value < G_N_ELEMENTS(temp_type))
+ return temp_type[value];
+
+ error("Temperature type %d reserved for future use", value);
+ return NULL;
+}
+
+static void destroy_watcher(gpointer user_data)
+{
+ struct watcher *watcher = user_data;
+
+ g_free(watcher->path);
+ g_free(watcher->srv);
+ g_free(watcher);
+}
+
+static void remove_watcher(gpointer user_data)
+{
+ struct watcher *watcher = user_data;
+
+ g_dbus_remove_watch(watcher->t->conn, watcher->id);
+}
+
+static void destroy_char(gpointer user_data)
+{
+ struct characteristic *c = user_data;
+
+ g_slist_free_full(c->desc, g_free);
+ g_free(c);
+}
+
+static void destroy_thermometer(gpointer user_data)
+{
+ struct thermometer *t = user_data;
+
+ if (t->attioid > 0)
+ btd_device_remove_attio_callback(t->dev, t->attioid);
+
+ if (t->attindid > 0)
+ g_attrib_unregister(t->attrib, t->attindid);
+
+ if (t->attnotid > 0)
+ g_attrib_unregister(t->attrib, t->attnotid);
+
+ if (t->attrib != NULL)
+ g_attrib_unref(t->attrib);
+
+ if (t->chars != NULL)
+ g_slist_free_full(t->chars, destroy_char);
+
+ if (t->fwatchers != NULL)
+ g_slist_free_full(t->fwatchers, remove_watcher);
+
+ dbus_connection_unref(t->conn);
+ btd_device_unref(t->dev);
+ g_free(t->svc_range);
+ g_free(t);
+}
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+ const struct thermometer *t = a;
+ const struct btd_device *dev = b;
+
+ if (dev == t->dev)
+ return 0;
+
+ return -1;
+}
+
+static gint cmp_watcher(gconstpointer a, gconstpointer b)
+{
+ const struct watcher *watcher = a;
+ const struct watcher *match = b;
+ int ret;
+
+ ret = g_strcmp0(watcher->srv, match->srv);
+ if (ret != 0)
+ return ret;
+
+ return g_strcmp0(watcher->path, match->path);
+}
+
+static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
+{
+ const struct characteristic *ch = a;
+ const char *uuid = b;
+
+ return g_strcmp0(ch->attr.uuid, uuid);
+}
+
+static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
+{
+ const struct characteristic *ch = a;
+ const uint16_t *handle = b;
+
+ return ch->attr.value_handle - *handle;
+}
+
+static gint cmp_descriptor(gconstpointer a, gconstpointer b)
+{
+ const struct descriptor *desc = a;
+ const bt_uuid_t *uuid = b;
+
+ return bt_uuid_cmp(&desc->uuid, uuid);
+}
+
+static struct characteristic *get_characteristic(struct thermometer *t,
+ const char *uuid)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(t->chars, uuid, cmp_char_uuid);
+ if (l == NULL)
+ return NULL;
+
+ return l->data;
+}
+
+static struct descriptor *get_descriptor(struct characteristic *ch,
+ const bt_uuid_t *uuid)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
+ if (l == NULL)
+ return NULL;
+
+ return l->data;
+}
+
+static void change_property(struct thermometer *t, const char *name,
+ gpointer value) {
+ if (g_strcmp0(name, "Intermediate") == 0) {
+ gboolean *intermediate = value;
+ if (t->intermediate == *intermediate)
+ return;
+
+ t->intermediate = *intermediate;
+ emit_property_changed(t->conn, device_get_path(t->dev),
+ THERMOMETER_INTERFACE, name,
+ DBUS_TYPE_BOOLEAN, &t->intermediate);
+ } else if (g_strcmp0(name, "Interval") == 0) {
+ uint16_t *interval = value;
+ if (t->has_interval && t->interval == *interval)
+ return;
+
+ t->has_interval = TRUE;
+ t->interval = *interval;
+ emit_property_changed(t->conn, device_get_path(t->dev),
+ THERMOMETER_INTERFACE, name,
+ DBUS_TYPE_UINT16, &t->interval);
+ } else if (g_strcmp0(name, "Maximum") == 0) {
+ uint16_t *max = value;
+ if (t->max == *max)
+ return;
+
+ t->max = *max;
+ emit_property_changed(t->conn, device_get_path(t->dev),
+ THERMOMETER_INTERFACE, name,
+ DBUS_TYPE_UINT16, &t->max);
+ } else if (g_strcmp0(name, "Minimum") == 0) {
+ uint16_t *min = value;
+ if (t->min == *min)
+ return;
+
+ t->min = *min;
+ emit_property_changed(t->conn, device_get_path(t->dev),
+ THERMOMETER_INTERFACE, name,
+ DBUS_TYPE_UINT16, &t->min);
+ } else
+ DBG("%s is not a thermometer property", name);
+}
+
+static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct descriptor *desc = user_data;
+ uint8_t value[ATT_MAX_MTU];
+ uint16_t max, min;
+ int vlen;
+
+ if (status != 0) {
+ DBG("Valid Range descriptor read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_read_resp(pdu, len, value, &vlen)) {
+ DBG("Protocol error\n");
+ return;
+ }
+
+ if (vlen < 4) {
+ DBG("Invalid range received");
+ return;
+ }
+
+ min = att_get_u16(&value[0]);
+ max = att_get_u16(&value[2]);
+
+ if (min == 0 || min > max) {
+ DBG("Invalid range");
+ return;
+ }
+
+ change_property(desc->ch->t, "Maximum", &max);
+ change_property(desc->ch->t, "Minimum", &min);
+}
+
+static void measurement_cb(guint8 status, const guint8 *pdu,
+ guint16 len, gpointer user_data)
+{
+ char *msg = user_data;
+
+ if (status != 0)
+ error("%s failed", msg);
+
+ g_free(msg);
+}
+
+static void process_thermometer_desc(struct descriptor *desc)
+{
+ struct characteristic *ch = desc->ch;
+ char uuidstr[MAX_LEN_UUID_STR];
+ bt_uuid_t btuuid;
+
+ bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+
+ if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
+ uint8_t atval[2];
+ uint16_t val;
+ char *msg;
+
+ if (g_strcmp0(ch->attr.uuid,
+ TEMPERATURE_MEASUREMENT_UUID) == 0) {
+ if (g_slist_length(ch->t->fwatchers) == 0)
+ return;
+
+ val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+ msg = g_strdup("Enable Temperature Measurement "
+ "indication");
+ } else if (g_strcmp0(ch->attr.uuid,
+ INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+ if (g_slist_length(ch->t->iwatchers) == 0)
+ return;
+
+ val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+ msg = g_strdup("Enable Intermediate Temperature "
+ "notification");
+ } else if (g_strcmp0(ch->attr.uuid,
+ MEASUREMENT_INTERVAL_UUID) == 0) {
+ val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+ msg = g_strdup("Enable Measurement Interval "
+ "indication");
+ } else
+ goto done;
+
+ att_put_u16(val, atval);
+ gatt_write_char(ch->t->attrib, desc->handle, atval, 2,
+ measurement_cb, msg);
+ return;
+ }
+
+ bt_uuid16_create(&btuuid, GATT_CHARAC_VALID_RANGE_UUID);
+
+ if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
+ MEASUREMENT_INTERVAL_UUID) == 0) {
+ gatt_read_char(ch->t->attrib, desc->handle, 0,
+ valid_range_desc_cb, desc);
+ return;
+ }
+
+done:
+ bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+ DBG("Ignored descriptor %s in characteristic %s", uuidstr,
+ ch->attr.uuid);
+}
+
+static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct characteristic *ch = user_data;
+ struct att_data_list *list;
+ uint8_t format;
+ int i;
+
+ if (status != 0) {
+ error("Discover all characteristic descriptors failed [%s]: %s",
+ ch->attr.uuid, att_ecode2str(status));
+ return;
+ }
+
+ list = dec_find_info_resp(pdu, len, &format);
+ if (list == NULL)
+ return;
+
+ for (i = 0; i < list->num; i++) {
+ struct descriptor *desc;
+ uint8_t *value;
+
+ value = list->data[i];
+ desc = g_new0(struct descriptor, 1);
+ desc->handle = att_get_u16(value);
+ desc->ch = ch;
+
+ if (format == 0x01)
+ desc->uuid = att_get_uuid16(&value[2]);
+ else
+ desc->uuid = att_get_uuid128(&value[2]);
+
+ ch->desc = g_slist_append(ch->desc, desc);
+ process_thermometer_desc(desc);
+ }
+
+ att_data_list_free(list);
+}
+
+static void read_temp_type_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct characteristic *ch = user_data;
+ struct thermometer *t = ch->t;
+ uint8_t value[ATT_MAX_MTU];
+ int vlen;
+
+ if (status != 0) {
+ DBG("Temperature Type value read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_read_resp(pdu, len, value, &vlen)) {
+ DBG("Protocol error.");
+ return;
+ }
+
+ if (vlen != 1) {
+ DBG("Invalid length for Temperature type");
+ return;
+ }
+
+ t->has_type = TRUE;
+ t->type = value[0];
+}
+
+static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct characteristic *ch = user_data;
+ uint8_t value[ATT_MAX_MTU];
+ uint16_t interval;
+ int vlen;
+
+ if (status != 0) {
+ DBG("Measurement Interval value read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (!dec_read_resp(pdu, len, value, &vlen)) {
+ DBG("Protocol error\n");
+ return;
+ }
+
+ if (vlen < 2) {
+ DBG("Invalid Interval received");
+ return;
+ }
+
+ interval = att_get_u16(&value[0]);
+ change_property(ch->t, "Interval", &interval);
+}
+
+static void process_thermometer_char(struct characteristic *ch)
+{
+ if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+ gboolean intermediate = TRUE;
+ change_property(ch->t, "Intermediate", &intermediate);
+ return;
+ } else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0)
+ gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
+ read_temp_type_cb, ch);
+ else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+ gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
+ read_interval_cb, ch);
+}
+
+static void configure_thermometer_cb(GSList *characteristics, guint8 status,
+ gpointer user_data)
+{
+ struct thermometer *t = user_data;
+ GSList *l;
+
+ if (status != 0) {
+ error("Discover thermometer characteristics: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ for (l = characteristics; l; l = l->next) {
+ struct gatt_char *c = l->data;
+ struct characteristic *ch;
+ uint16_t start, end;
+
+ ch = g_new0(struct characteristic, 1);
+ ch->attr.handle = c->handle;
+ ch->attr.properties = c->properties;
+ ch->attr.value_handle = c->value_handle;
+ memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+ ch->t = t;
+
+ t->chars = g_slist_append(t->chars, ch);
+
+ process_thermometer_char(ch);
+
+ start = c->value_handle + 1;
+
+ if (l->next != NULL) {
+ struct gatt_char *c = l->next->data;
+ if (start == c->handle)
+ continue;
+ end = c->handle - 1;
+ } else if (c->value_handle != t->svc_range->end)
+ end = t->svc_range->end;
+ else
+ continue;
+
+ gatt_find_info(t->attrib, start, end, discover_desc_cb, ch);
+ }
+}
+
+static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct thermometer *t = data;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dict_append_entry(&dict, "Intermediate", DBUS_TYPE_BOOLEAN,
+ &t->intermediate);
+
+ if (t->has_interval) {
+ dict_append_entry(&dict, "Interval", DBUS_TYPE_UINT16,
+ &t->interval);
+ dict_append_entry(&dict, "Maximum", DBUS_TYPE_UINT16, &t->max);
+ dict_append_entry(&dict, "Minimum", DBUS_TYPE_UINT16, &t->min);
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static void write_interval_cb (guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct tmp_interval_data *data = user_data;
+
+ if (status != 0) {
+ error("Interval Write Request failed %s",
+ att_ecode2str(status));
+ goto done;
+ }
+
+ if (!dec_write_resp(pdu, len)) {
+ error("Interval Write Request: protocol error");
+ goto done;
+ }
+
+ change_property(data->thermometer, "Interval", &data->interval);
+
+done:
+ g_free(user_data);
+}
+
+static DBusMessage *write_attr_interval(struct thermometer *t, DBusMessage *msg,
+ uint16_t value)
+{
+ struct tmp_interval_data *data;
+ struct characteristic *ch;
+ uint8_t atval[2];
+
+ if (t->attrib == NULL)
+ return btd_error_not_connected(msg);
+
+ ch = get_characteristic(t, MEASUREMENT_INTERVAL_UUID);
+ if (ch == NULL)
+ return btd_error_not_available(msg);
+
+ if (value < t->min || value > t->max)
+ return btd_error_invalid_args(msg);
+
+ att_put_u16(value, &atval[0]);
+
+ data = g_new0(struct tmp_interval_data, 1);
+ data->thermometer = t;
+ data->interval = value;
+ gatt_write_char(t->attrib, ch->attr.value_handle, atval, 2,
+ write_interval_cb, data);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct thermometer *t = data;
+ const char *property;
+ DBusMessageIter iter;
+ DBusMessageIter sub;
+ uint16_t value;
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return btd_error_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &property);
+ if (g_strcmp0("Interval", property) != 0)
+ return btd_error_invalid_args(msg);
+
+ if (!t->has_interval)
+ return btd_error_not_available(msg);
+
+ dbus_message_iter_next(&iter);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&iter, &sub);
+
+ if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&sub, &value);
+
+ return write_attr_interval(t, msg, value);
+}
+
+static void enable_final_measurement(struct thermometer *t)
+{
+ struct characteristic *ch;
+ struct descriptor *desc;
+ bt_uuid_t btuuid;
+ uint8_t atval[2];
+ char *msg;
+
+ if (t->attrib == NULL)
+ return;
+
+ ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
+ if (ch == NULL) {
+ DBG("Temperature measurement characteristic not found");
+ return;
+ }
+
+ bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ desc = get_descriptor(ch, &btuuid);
+ if (desc == NULL) {
+ DBG("Client characteristic configuration descriptor not found");
+ return;
+ }
+
+ atval[0] = 0x02;
+ atval[1] = 0x00;
+ msg = g_strdup("Enable final measurement");
+ gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void enable_intermediate_measurement(struct thermometer *t)
+{
+ struct characteristic *ch;
+ struct descriptor *desc;
+ bt_uuid_t btuuid;
+ uint8_t atval[2];
+ char *msg;
+
+ if (t->attrib == NULL)
+ return;
+
+ ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
+ if (ch == NULL) {
+ DBG("Intermediate measurement characteristic not found");
+ return;
+ }
+
+ bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ desc = get_descriptor(ch, &btuuid);
+ if (desc == NULL) {
+ DBG("Client characteristic configuration descriptor not found");
+ return;
+ }
+
+ atval[0] = 0x01;
+ atval[1] = 0x00;
+ msg = g_strdup("Enable intermediate measurement");
+ gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void disable_final_measurement(struct thermometer *t)
+{
+ struct characteristic *ch;
+ struct descriptor *desc;
+ bt_uuid_t btuuid;
+ uint8_t atval[2];
+ char *msg;
+
+ if (t->attrib == NULL)
+ return;
+
+ ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
+ if (ch == NULL) {
+ DBG("Temperature measurement characteristic not found");
+ return;
+ }
+
+ bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ desc = get_descriptor(ch, &btuuid);
+ if (desc == NULL) {
+ DBG("Client characteristic configuration descriptor not found");
+ return;
+ }
+
+ atval[0] = 0x00;
+ atval[1] = 0x00;
+ msg = g_strdup("Disable final measurement");
+ gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void disable_intermediate_measurement(struct thermometer *t)
+{
+ struct characteristic *ch;
+ struct descriptor *desc;
+ bt_uuid_t btuuid;
+ uint8_t atval[2];
+ char *msg;
+
+ if (t->attrib == NULL)
+ return;
+
+ ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
+ if (ch == NULL) {
+ DBG("Intermediate measurement characteristic not found");
+ return;
+ }
+
+ bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ desc = get_descriptor(ch, &btuuid);
+ if (desc == NULL) {
+ DBG("Client characteristic configuration descriptor not found");
+ return;
+ }
+
+ atval[0] = 0x00;
+ atval[1] = 0x00;
+ msg = g_strdup("Disable intermediate measurement");
+ gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void remove_int_watcher(struct thermometer *t, struct watcher *w)
+{
+ if (!g_slist_find(t->iwatchers, w))
+ return;
+
+ t->iwatchers = g_slist_remove(t->iwatchers, w);
+
+ if (g_slist_length(t->iwatchers) == 0)
+ disable_intermediate_measurement(t);
+}
+
+static void watcher_exit(DBusConnection *conn, void *user_data)
+{
+ struct watcher *watcher = user_data;
+ struct thermometer *t = watcher->t;
+
+ DBG("Thermometer watcher %s disconnected", watcher->path);
+
+ remove_int_watcher(t, watcher);
+
+ t->fwatchers = g_slist_remove(t->fwatchers, watcher);
+ g_dbus_remove_watch(watcher->t->conn, watcher->id);
+
+ if (g_slist_length(t->fwatchers) == 0)
+ disable_final_measurement(t);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+ const char *path)
+{
+ struct watcher *match;
+ GSList *l;
+
+ match = g_new0(struct watcher, 1);
+ match->srv = g_strdup(sender);
+ match->path = g_strdup(path);
+
+ l = g_slist_find_custom(list, match, cmp_watcher);
+ destroy_watcher(match);
+
+ if (l != NULL)
+ return l->data;
+
+ return NULL;
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *sender = dbus_message_get_sender(msg);
+ struct thermometer *t = data;
+ struct watcher *watcher;
+ char *path;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ watcher = find_watcher(t->fwatchers, sender, path);
+ if (watcher != NULL)
+ return btd_error_already_exists(msg);
+
+ DBG("Thermometer watcher %s registered", path);
+
+ watcher = g_new0(struct watcher, 1);
+ watcher->srv = g_strdup(sender);
+ watcher->path = g_strdup(path);
+ watcher->t = t;
+ watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
+ watcher, destroy_watcher);
+
+ if (g_slist_length(t->fwatchers) == 0)
+ enable_final_measurement(t);
+
+ t->fwatchers = g_slist_prepend(t->fwatchers, watcher);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *sender = dbus_message_get_sender(msg);
+ struct thermometer *t = data;
+ struct watcher *watcher;
+ char *path;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ watcher = find_watcher(t->fwatchers, sender, path);
+ if (watcher == NULL)
+ return btd_error_does_not_exist(msg);
+
+ DBG("Thermometer watcher %s unregistered", path);
+
+ remove_int_watcher(t, watcher);
+
+ t->fwatchers = g_slist_remove(t->fwatchers, watcher);
+ g_dbus_remove_watch(watcher->t->conn, watcher->id);
+
+ if (g_slist_length(t->fwatchers) == 0)
+ disable_final_measurement(t);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *enable_intermediate(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *sender = dbus_message_get_sender(msg);
+ struct thermometer *t = data;
+ struct watcher *watcher;
+ char *path;
+
+ if (!t->intermediate)
+ return btd_error_not_supported(msg);
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ watcher = find_watcher(t->fwatchers, sender, path);
+ if (watcher == NULL)
+ return btd_error_does_not_exist(msg);
+
+ if (find_watcher(t->iwatchers, sender, path))
+ return btd_error_already_exists(msg);
+
+ DBG("Intermediate measurement watcher %s registered", path);
+
+ if (g_slist_length(t->iwatchers) == 0)
+ enable_intermediate_measurement(t);
+
+ t->iwatchers = g_slist_prepend(t->iwatchers, watcher);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *sender = dbus_message_get_sender(msg);
+ struct thermometer *t = data;
+ struct watcher *watcher;
+ char *path;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ watcher = find_watcher(t->iwatchers, sender, path);
+ if (watcher == NULL)
+ return btd_error_does_not_exist(msg);
+
+ DBG("Intermediate measurement %s unregistered", path);
+
+ remove_int_watcher(t, watcher);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable thermometer_methods[] = {
+ { GDBUS_METHOD("GetProperties",
+ NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+ get_properties) },
+ { GDBUS_ASYNC_METHOD("SetProperty",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
+ set_property) },
+ { GDBUS_METHOD("RegisterWatcher",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ register_watcher) },
+ { GDBUS_METHOD("UnregisterWatcher",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ unregister_watcher) },
+ { GDBUS_METHOD("EnableIntermediateMeasurement",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ enable_intermediate) },
+ { GDBUS_METHOD("DisableIntermediateMeasurement",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ disable_intermediate) },
+ { }
+};
+
+static const GDBusSignalTable thermometer_signals[] = {
+ { GDBUS_SIGNAL("PropertyChanged",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+ { }
+};
+
+static void update_watcher(gpointer data, gpointer user_data)
+{
+ struct watcher *w = data;
+ struct measurement *m = user_data;
+ DBusConnection *conn = w->t->conn;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call(w->srv, w->path,
+ "org.bluez.ThermometerWatcher",
+ "MeasurementReceived");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dict_append_entry(&dict, "Exponent", DBUS_TYPE_INT16, &m->exp);
+ dict_append_entry(&dict, "Mantissa", DBUS_TYPE_INT32, &m->mant);
+ dict_append_entry(&dict, "Unit", DBUS_TYPE_STRING, &m->unit);
+
+ if (m->suptime)
+ dict_append_entry(&dict, "Time", DBUS_TYPE_UINT64, &m->time);
+
+ dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &m->type);
+ dict_append_entry(&dict, "Measurement", DBUS_TYPE_STRING, &m->value);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ dbus_message_set_no_reply(msg, TRUE);
+ g_dbus_send_message(conn, msg);
+}
+
+static void recv_measurement(struct thermometer *t, struct measurement *m)
+{
+ GSList *wlist;
+
+ if (g_strcmp0(m->value, "Intermediate") == 0)
+ wlist = t->iwatchers;
+ else
+ wlist = t->fwatchers;
+
+ g_slist_foreach(wlist, update_watcher, m);
+}
+
+static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
+ uint16_t len, gboolean final)
+{
+ struct measurement m;
+ const char *type;
+ uint8_t flags;
+ uint32_t raw;
+
+ if (len < 4) {
+ DBG("Mandatory flags are not provided");
+ return;
+ }
+
+ flags = pdu[3];
+ if (flags & TEMP_UNITS)
+ m.unit = "Fahrenheit";
+ else
+ m.unit = "Celsius";
+
+ if (len < 8) {
+ DBG("Temperature measurement value is not provided");
+ return;
+ }
+
+ raw = att_get_u32(&pdu[4]);
+ m.mant = raw & 0x00FFFFFF;
+ m.exp = ((int32_t) raw) >> 24;
+
+ if (m.mant & 0x00800000) {
+ /* convert to C2 negative value */
+ m.mant = m.mant - FLOAT_MAX_MANTISSA;
+ }
+
+ if (flags & TEMP_TIME_STAMP) {
+ struct tm ts;
+ time_t time;
+
+ if (len < 15) {
+ DBG("Can't get time stamp value");
+ return;
+ }
+
+ ts.tm_year = att_get_u16(&pdu[8]) - 1900;
+ ts.tm_mon = pdu[10] - 1;
+ ts.tm_mday = pdu[11];
+ ts.tm_hour = pdu[12];
+ ts.tm_min = pdu[13];
+ ts.tm_sec = pdu[14];
+ ts.tm_isdst = -1;
+
+ time = mktime(&ts);
+ m.time = (uint64_t) time;
+ m.suptime = TRUE;
+ } else
+ m.suptime = FALSE;
+
+ if (flags & TEMP_TYPE) {
+ uint8_t index;
+
+ if (m.suptime && len >= 16)
+ index = 15;
+ else if (!m.suptime && len >= 9)
+ index = 9;
+ else {
+ DBG("Can't get temperature type");
+ return;
+ }
+
+ type = temptype2str(pdu[index]);
+ } else if (t->has_type)
+ type = temptype2str(t->type);
+ else
+ type = NULL;
+
+ m.type = type ? g_strdup(type) : NULL;
+ m.value = final ? "Final" : "Intermediate";
+
+ recv_measurement(t, &m);
+ g_free(m.type);
+}
+
+static void proc_measurement_interval(struct thermometer *t, const uint8_t *pdu,
+ uint16_t len)
+{
+ uint16_t interval;
+
+ if (len < 5) {
+ DBG("Measurement interval value is not provided");
+ return;
+ }
+
+ interval = att_get_u16(&pdu[3]);
+
+ change_property(t, "Interval", &interval);
+}
+
+static void ind_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+ struct thermometer *t = user_data;
+ const struct characteristic *ch;
+ uint8_t opdu[ATT_MAX_MTU];
+ uint16_t handle, olen;
+ GSList *l;
+
+ if (len < 3) {
+ DBG("Bad pdu received");
+ return;
+ }
+
+ handle = att_get_u16(&pdu[1]);
+ l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
+ if (l == NULL) {
+ DBG("Unexpected handle: 0x%04x", handle);
+ return;
+ }
+
+ ch = l->data;
+
+ if (g_strcmp0(ch->attr.uuid, TEMPERATURE_MEASUREMENT_UUID) == 0)
+ proc_measurement(t, pdu, len, TRUE);
+ else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+ proc_measurement_interval(t, pdu, len);
+
+ olen = enc_confirmation(opdu, sizeof(opdu));
+
+ if (olen > 0)
+ g_attrib_send(t->attrib, 0, opdu[0], opdu, olen, NULL, NULL,
+ NULL);
+}
+
+static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+ struct thermometer *t = user_data;
+ const struct characteristic *ch;
+ uint16_t handle;
+ GSList *l;
+
+ if (len < 3) {
+ DBG("Bad pdu received");
+ return;
+ }
+
+ handle = att_get_u16(&pdu[1]);
+ l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
+ if (l == NULL) {
+ DBG("Unexpected handle: 0x%04x", handle);
+ return;
+ }
+
+ ch = l->data;
+ if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0)
+ proc_measurement(t, pdu, len, FALSE);
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+ struct thermometer *t = user_data;
+
+ t->attrib = g_attrib_ref(attrib);
+
+ t->attindid = g_attrib_register(t->attrib, ATT_OP_HANDLE_IND,
+ ind_handler, t, NULL);
+ t->attnotid = g_attrib_register(t->attrib, ATT_OP_HANDLE_NOTIFY,
+ notif_handler, t, NULL);
+ gatt_discover_char(t->attrib, t->svc_range->start, t->svc_range->end,
+ NULL, configure_thermometer_cb, t);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+ struct thermometer *t = user_data;
+
+ DBG("GATT Disconnected");
+
+ if (t->attindid > 0) {
+ g_attrib_unregister(t->attrib, t->attindid);
+ t->attindid = 0;
+ }
+
+ if (t->attnotid > 0) {
+ g_attrib_unregister(t->attrib, t->attnotid);
+ t->attnotid = 0;
+ }
+
+ g_attrib_unref(t->attrib);
+ t->attrib = NULL;
+}
+
+int thermometer_register(DBusConnection *connection, struct btd_device *device,
+ struct gatt_primary *tattr)
+{
+ const gchar *path = device_get_path(device);
+ struct thermometer *t;
+
+ t = g_new0(struct thermometer, 1);
+ t->conn = dbus_connection_ref(connection);
+ t->dev = btd_device_ref(device);
+ t->svc_range = g_new0(struct att_range, 1);
+ t->svc_range->start = tattr->range.start;
+ t->svc_range->end = tattr->range.end;
+
+ if (!g_dbus_register_interface(t->conn, path, THERMOMETER_INTERFACE,
+ thermometer_methods, thermometer_signals,
+ NULL, t, destroy_thermometer)) {
+ error("D-Bus failed to register %s interface",
+ THERMOMETER_INTERFACE);
+ destroy_thermometer(t);
+ return -EIO;
+ }
+
+ thermometers = g_slist_prepend(thermometers, t);
+
+ t->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
+ attio_disconnected_cb, t);
+ return 0;
+}
+
+void thermometer_unregister(struct btd_device *device)
+{
+ struct thermometer *t;
+ GSList *l;
+
+ l = g_slist_find_custom(thermometers, device, cmp_device);
+ if (l == NULL)
+ return;
+
+ t = l->data;
+ thermometers = g_slist_remove(thermometers, t);
+ g_dbus_unregister_interface(t->conn, device_get_path(t->dev),
+ THERMOMETER_INTERFACE);
+}
diff --git a/profiles/thermometer/thermometer.h b/profiles/thermometer/thermometer.h
new file mode 100644
index 0000000..330503c
--- /dev/null
+++ b/profiles/thermometer/thermometer.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ * 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
+ *
+ */
+
+int thermometer_register(DBusConnection *connection, struct btd_device *device,
+ struct gatt_primary *tattr);
+void thermometer_unregister(struct btd_device *device);
diff --git a/thermometer/main.c b/thermometer/main.c
deleted file mode 100644
index 4447b52..0000000
--- a/thermometer/main.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- * 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 <stdint.h>
-#include <glib.h>
-#include <errno.h>
-#include <gdbus.h>
-
-#include "plugin.h"
-#include "manager.h"
-#include "hcid.h"
-#include "log.h"
-
-static DBusConnection *connection = NULL;
-
-static int thermometer_init(void)
-{
- if (!main_opts.gatt_enabled) {
- DBG("GATT is disabled");
- return -ENOTSUP;
- }
-
- connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
- if (connection == NULL)
- return -EIO;
-
- if (thermometer_manager_init(connection) < 0) {
- dbus_connection_unref(connection);
- return -EIO;
- }
-
- return 0;
-}
-
-static void thermometer_exit(void)
-{
- if (!main_opts.gatt_enabled)
- return;
-
- thermometer_manager_exit();
-
- dbus_connection_unref(connection);
- connection = NULL;
-}
-
-BLUETOOTH_PLUGIN_DEFINE(thermometer, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
- thermometer_init, thermometer_exit)
diff --git a/thermometer/manager.c b/thermometer/manager.c
deleted file mode 100644
index 3d5452b..0000000
--- a/thermometer/manager.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- * 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
- *
- */
-
-#include <gdbus.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-
-#include "adapter.h"
-#include "device.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "thermometer.h"
-#include "manager.h"
-
-static DBusConnection *connection = NULL;
-
-static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
-{
- const struct gatt_primary *prim = a;
- const char *uuid = b;
-
- return g_strcmp0(prim->uuid, uuid);
-}
-
-static int thermometer_driver_probe(struct btd_device *device, GSList *uuids)
-{
- struct gatt_primary *tattr;
- GSList *primaries, *l;
-
- primaries = btd_device_get_primaries(device);
-
- l = g_slist_find_custom(primaries, HEALTH_THERMOMETER_UUID,
- primary_uuid_cmp);
- if (l == NULL)
- return -EINVAL;
-
- tattr = l->data;
-
- return thermometer_register(connection, device, tattr);
-}
-
-static void thermometer_driver_remove(struct btd_device *device)
-{
- thermometer_unregister(device);
-}
-
-static struct btd_device_driver thermometer_device_driver = {
- .name = "thermometer-device-driver",
- .uuids = BTD_UUIDS(HEALTH_THERMOMETER_UUID),
- .probe = thermometer_driver_probe,
- .remove = thermometer_driver_remove
-};
-
-int thermometer_manager_init(DBusConnection *conn)
-{
- int ret;
-
- ret = btd_register_device_driver(&thermometer_device_driver);
- if (ret < 0)
- return ret;
-
- connection = dbus_connection_ref(conn);
- return 0;
-}
-
-void thermometer_manager_exit(void)
-{
- btd_unregister_device_driver(&thermometer_device_driver);
-
- dbus_connection_unref(connection);
- connection = NULL;
-}
diff --git a/thermometer/manager.h b/thermometer/manager.h
deleted file mode 100644
index ed928ad..0000000
--- a/thermometer/manager.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- * 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
- *
- */
-
-int thermometer_manager_init(DBusConnection *conn);
-void thermometer_manager_exit(void);
diff --git a/thermometer/thermometer.c b/thermometer/thermometer.c
deleted file mode 100644
index 85f0811..0000000
--- a/thermometer/thermometer.c
+++ /dev/null
@@ -1,1265 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- * 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 <gdbus.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-
-#include "dbus-common.h"
-#include "adapter.h"
-#include "device.h"
-#include "error.h"
-#include "log.h"
-#include "gattrib.h"
-#include "attio.h"
-#include "att.h"
-#include "gatt.h"
-#include "thermometer.h"
-
-#define THERMOMETER_INTERFACE "org.bluez.Thermometer"
-
-/* Temperature measurement flag fields */
-#define TEMP_UNITS 0x01
-#define TEMP_TIME_STAMP 0x02
-#define TEMP_TYPE 0x04
-
-#define FLOAT_MAX_MANTISSA 16777216 /* 2^24 */
-
-struct thermometer {
- DBusConnection *conn; /* The connection to the bus */
- struct btd_device *dev; /* Device reference */
- GAttrib *attrib; /* GATT connection */
- struct att_range *svc_range; /* Thermometer range */
- guint attioid; /* Att watcher id */
- guint attindid; /* Att incications id */
- guint attnotid; /* Att notifications id */
- GSList *chars; /* Characteristics */
- GSList *fwatchers; /* Final measurements */
- GSList *iwatchers; /* Intermediate measurements */
- gboolean intermediate;
- uint8_t type;
- uint16_t interval;
- uint16_t max;
- uint16_t min;
- gboolean has_type;
- gboolean has_interval;
-};
-
-struct characteristic {
- struct gatt_char attr; /* Characteristic */
- GSList *desc; /* Descriptors */
- struct thermometer *t; /* Thermometer where the char belongs */
-};
-
-struct descriptor {
- struct characteristic *ch;
- uint16_t handle;
- bt_uuid_t uuid;
-};
-
-struct watcher {
- struct thermometer *t;
- guint id;
- char *srv;
- char *path;
-};
-
-struct measurement {
- int16_t exp;
- int32_t mant;
- uint64_t time;
- gboolean suptime;
- char *unit;
- char *type;
- char *value;
-};
-
-struct tmp_interval_data {
- struct thermometer *thermometer;
- uint16_t interval;
-};
-
-static GSList *thermometers = NULL;
-
-const char *temp_type[] = {
- "<reserved>",
- "Armpit",
- "Body",
- "Ear",
- "Finger",
- "Intestines",
- "Mouth",
- "Rectum",
- "Toe",
- "Tympanum"
-};
-
-static const gchar *temptype2str(uint8_t value)
-{
- if (value > 0 && value < G_N_ELEMENTS(temp_type))
- return temp_type[value];
-
- error("Temperature type %d reserved for future use", value);
- return NULL;
-}
-
-static void destroy_watcher(gpointer user_data)
-{
- struct watcher *watcher = user_data;
-
- g_free(watcher->path);
- g_free(watcher->srv);
- g_free(watcher);
-}
-
-static void remove_watcher(gpointer user_data)
-{
- struct watcher *watcher = user_data;
-
- g_dbus_remove_watch(watcher->t->conn, watcher->id);
-}
-
-static void destroy_char(gpointer user_data)
-{
- struct characteristic *c = user_data;
-
- g_slist_free_full(c->desc, g_free);
- g_free(c);
-}
-
-static void destroy_thermometer(gpointer user_data)
-{
- struct thermometer *t = user_data;
-
- if (t->attioid > 0)
- btd_device_remove_attio_callback(t->dev, t->attioid);
-
- if (t->attindid > 0)
- g_attrib_unregister(t->attrib, t->attindid);
-
- if (t->attnotid > 0)
- g_attrib_unregister(t->attrib, t->attnotid);
-
- if (t->attrib != NULL)
- g_attrib_unref(t->attrib);
-
- if (t->chars != NULL)
- g_slist_free_full(t->chars, destroy_char);
-
- if (t->fwatchers != NULL)
- g_slist_free_full(t->fwatchers, remove_watcher);
-
- dbus_connection_unref(t->conn);
- btd_device_unref(t->dev);
- g_free(t->svc_range);
- g_free(t);
-}
-
-static gint cmp_device(gconstpointer a, gconstpointer b)
-{
- const struct thermometer *t = a;
- const struct btd_device *dev = b;
-
- if (dev == t->dev)
- return 0;
-
- return -1;
-}
-
-static gint cmp_watcher(gconstpointer a, gconstpointer b)
-{
- const struct watcher *watcher = a;
- const struct watcher *match = b;
- int ret;
-
- ret = g_strcmp0(watcher->srv, match->srv);
- if (ret != 0)
- return ret;
-
- return g_strcmp0(watcher->path, match->path);
-}
-
-static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
-{
- const struct characteristic *ch = a;
- const char *uuid = b;
-
- return g_strcmp0(ch->attr.uuid, uuid);
-}
-
-static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
-{
- const struct characteristic *ch = a;
- const uint16_t *handle = b;
-
- return ch->attr.value_handle - *handle;
-}
-
-static gint cmp_descriptor(gconstpointer a, gconstpointer b)
-{
- const struct descriptor *desc = a;
- const bt_uuid_t *uuid = b;
-
- return bt_uuid_cmp(&desc->uuid, uuid);
-}
-
-static struct characteristic *get_characteristic(struct thermometer *t,
- const char *uuid)
-{
- GSList *l;
-
- l = g_slist_find_custom(t->chars, uuid, cmp_char_uuid);
- if (l == NULL)
- return NULL;
-
- return l->data;
-}
-
-static struct descriptor *get_descriptor(struct characteristic *ch,
- const bt_uuid_t *uuid)
-{
- GSList *l;
-
- l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
- if (l == NULL)
- return NULL;
-
- return l->data;
-}
-
-static void change_property(struct thermometer *t, const char *name,
- gpointer value) {
- if (g_strcmp0(name, "Intermediate") == 0) {
- gboolean *intermediate = value;
- if (t->intermediate == *intermediate)
- return;
-
- t->intermediate = *intermediate;
- emit_property_changed(t->conn, device_get_path(t->dev),
- THERMOMETER_INTERFACE, name,
- DBUS_TYPE_BOOLEAN, &t->intermediate);
- } else if (g_strcmp0(name, "Interval") == 0) {
- uint16_t *interval = value;
- if (t->has_interval && t->interval == *interval)
- return;
-
- t->has_interval = TRUE;
- t->interval = *interval;
- emit_property_changed(t->conn, device_get_path(t->dev),
- THERMOMETER_INTERFACE, name,
- DBUS_TYPE_UINT16, &t->interval);
- } else if (g_strcmp0(name, "Maximum") == 0) {
- uint16_t *max = value;
- if (t->max == *max)
- return;
-
- t->max = *max;
- emit_property_changed(t->conn, device_get_path(t->dev),
- THERMOMETER_INTERFACE, name,
- DBUS_TYPE_UINT16, &t->max);
- } else if (g_strcmp0(name, "Minimum") == 0) {
- uint16_t *min = value;
- if (t->min == *min)
- return;
-
- t->min = *min;
- emit_property_changed(t->conn, device_get_path(t->dev),
- THERMOMETER_INTERFACE, name,
- DBUS_TYPE_UINT16, &t->min);
- } else
- DBG("%s is not a thermometer property", name);
-}
-
-static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
-{
- struct descriptor *desc = user_data;
- uint8_t value[ATT_MAX_MTU];
- uint16_t max, min;
- int vlen;
-
- if (status != 0) {
- DBG("Valid Range descriptor read failed: %s",
- att_ecode2str(status));
- return;
- }
-
- if (!dec_read_resp(pdu, len, value, &vlen)) {
- DBG("Protocol error\n");
- return;
- }
-
- if (vlen < 4) {
- DBG("Invalid range received");
- return;
- }
-
- min = att_get_u16(&value[0]);
- max = att_get_u16(&value[2]);
-
- if (min == 0 || min > max) {
- DBG("Invalid range");
- return;
- }
-
- change_property(desc->ch->t, "Maximum", &max);
- change_property(desc->ch->t, "Minimum", &min);
-}
-
-static void measurement_cb(guint8 status, const guint8 *pdu,
- guint16 len, gpointer user_data)
-{
- char *msg = user_data;
-
- if (status != 0)
- error("%s failed", msg);
-
- g_free(msg);
-}
-
-static void process_thermometer_desc(struct descriptor *desc)
-{
- struct characteristic *ch = desc->ch;
- char uuidstr[MAX_LEN_UUID_STR];
- bt_uuid_t btuuid;
-
- bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-
- if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
- uint8_t atval[2];
- uint16_t val;
- char *msg;
-
- if (g_strcmp0(ch->attr.uuid,
- TEMPERATURE_MEASUREMENT_UUID) == 0) {
- if (g_slist_length(ch->t->fwatchers) == 0)
- return;
-
- val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
- msg = g_strdup("Enable Temperature Measurement "
- "indication");
- } else if (g_strcmp0(ch->attr.uuid,
- INTERMEDIATE_TEMPERATURE_UUID) == 0) {
- if (g_slist_length(ch->t->iwatchers) == 0)
- return;
-
- val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
- msg = g_strdup("Enable Intermediate Temperature "
- "notification");
- } else if (g_strcmp0(ch->attr.uuid,
- MEASUREMENT_INTERVAL_UUID) == 0) {
- val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
- msg = g_strdup("Enable Measurement Interval "
- "indication");
- } else
- goto done;
-
- att_put_u16(val, atval);
- gatt_write_char(ch->t->attrib, desc->handle, atval, 2,
- measurement_cb, msg);
- return;
- }
-
- bt_uuid16_create(&btuuid, GATT_CHARAC_VALID_RANGE_UUID);
-
- if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
- MEASUREMENT_INTERVAL_UUID) == 0) {
- gatt_read_char(ch->t->attrib, desc->handle, 0,
- valid_range_desc_cb, desc);
- return;
- }
-
-done:
- bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
- DBG("Ignored descriptor %s in characteristic %s", uuidstr,
- ch->attr.uuid);
-}
-
-static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
-{
- struct characteristic *ch = user_data;
- struct att_data_list *list;
- uint8_t format;
- int i;
-
- if (status != 0) {
- error("Discover all characteristic descriptors failed [%s]: %s",
- ch->attr.uuid, att_ecode2str(status));
- return;
- }
-
- list = dec_find_info_resp(pdu, len, &format);
- if (list == NULL)
- return;
-
- for (i = 0; i < list->num; i++) {
- struct descriptor *desc;
- uint8_t *value;
-
- value = list->data[i];
- desc = g_new0(struct descriptor, 1);
- desc->handle = att_get_u16(value);
- desc->ch = ch;
-
- if (format == 0x01)
- desc->uuid = att_get_uuid16(&value[2]);
- else
- desc->uuid = att_get_uuid128(&value[2]);
-
- ch->desc = g_slist_append(ch->desc, desc);
- process_thermometer_desc(desc);
- }
-
- att_data_list_free(list);
-}
-
-static void read_temp_type_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
-{
- struct characteristic *ch = user_data;
- struct thermometer *t = ch->t;
- uint8_t value[ATT_MAX_MTU];
- int vlen;
-
- if (status != 0) {
- DBG("Temperature Type value read failed: %s",
- att_ecode2str(status));
- return;
- }
-
- if (!dec_read_resp(pdu, len, value, &vlen)) {
- DBG("Protocol error.");
- return;
- }
-
- if (vlen != 1) {
- DBG("Invalid length for Temperature type");
- return;
- }
-
- t->has_type = TRUE;
- t->type = value[0];
-}
-
-static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
-{
- struct characteristic *ch = user_data;
- uint8_t value[ATT_MAX_MTU];
- uint16_t interval;
- int vlen;
-
- if (status != 0) {
- DBG("Measurement Interval value read failed: %s",
- att_ecode2str(status));
- return;
- }
-
- if (!dec_read_resp(pdu, len, value, &vlen)) {
- DBG("Protocol error\n");
- return;
- }
-
- if (vlen < 2) {
- DBG("Invalid Interval received");
- return;
- }
-
- interval = att_get_u16(&value[0]);
- change_property(ch->t, "Interval", &interval);
-}
-
-static void process_thermometer_char(struct characteristic *ch)
-{
- if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
- gboolean intermediate = TRUE;
- change_property(ch->t, "Intermediate", &intermediate);
- return;
- } else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0)
- gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
- read_temp_type_cb, ch);
- else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
- gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
- read_interval_cb, ch);
-}
-
-static void configure_thermometer_cb(GSList *characteristics, guint8 status,
- gpointer user_data)
-{
- struct thermometer *t = user_data;
- GSList *l;
-
- if (status != 0) {
- error("Discover thermometer characteristics: %s",
- att_ecode2str(status));
- return;
- }
-
- for (l = characteristics; l; l = l->next) {
- struct gatt_char *c = l->data;
- struct characteristic *ch;
- uint16_t start, end;
-
- ch = g_new0(struct characteristic, 1);
- ch->attr.handle = c->handle;
- ch->attr.properties = c->properties;
- ch->attr.value_handle = c->value_handle;
- memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
- ch->t = t;
-
- t->chars = g_slist_append(t->chars, ch);
-
- process_thermometer_char(ch);
-
- start = c->value_handle + 1;
-
- if (l->next != NULL) {
- struct gatt_char *c = l->next->data;
- if (start == c->handle)
- continue;
- end = c->handle - 1;
- } else if (c->value_handle != t->svc_range->end)
- end = t->svc_range->end;
- else
- continue;
-
- gatt_find_info(t->attrib, start, end, discover_desc_cb, ch);
- }
-}
-
-static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct thermometer *t = data;
- DBusMessageIter iter;
- DBusMessageIter dict;
- DBusMessage *reply;
-
- reply = dbus_message_new_method_return(msg);
- if (reply == NULL)
- return NULL;
-
- dbus_message_iter_init_append(reply, &iter);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
- dict_append_entry(&dict, "Intermediate", DBUS_TYPE_BOOLEAN,
- &t->intermediate);
-
- if (t->has_interval) {
- dict_append_entry(&dict, "Interval", DBUS_TYPE_UINT16,
- &t->interval);
- dict_append_entry(&dict, "Maximum", DBUS_TYPE_UINT16, &t->max);
- dict_append_entry(&dict, "Minimum", DBUS_TYPE_UINT16, &t->min);
- }
-
- dbus_message_iter_close_container(&iter, &dict);
-
- return reply;
-}
-
-static void write_interval_cb (guint8 status, const guint8 *pdu, guint16 len,
- gpointer user_data)
-{
- struct tmp_interval_data *data = user_data;
-
- if (status != 0) {
- error("Interval Write Request failed %s",
- att_ecode2str(status));
- goto done;
- }
-
- if (!dec_write_resp(pdu, len)) {
- error("Interval Write Request: protocol error");
- goto done;
- }
-
- change_property(data->thermometer, "Interval", &data->interval);
-
-done:
- g_free(user_data);
-}
-
-static DBusMessage *write_attr_interval(struct thermometer *t, DBusMessage *msg,
- uint16_t value)
-{
- struct tmp_interval_data *data;
- struct characteristic *ch;
- uint8_t atval[2];
-
- if (t->attrib == NULL)
- return btd_error_not_connected(msg);
-
- ch = get_characteristic(t, MEASUREMENT_INTERVAL_UUID);
- if (ch == NULL)
- return btd_error_not_available(msg);
-
- if (value < t->min || value > t->max)
- return btd_error_invalid_args(msg);
-
- att_put_u16(value, &atval[0]);
-
- data = g_new0(struct tmp_interval_data, 1);
- data->thermometer = t;
- data->interval = value;
- gatt_write_char(t->attrib, ch->attr.value_handle, atval, 2,
- write_interval_cb, data);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct thermometer *t = data;
- const char *property;
- DBusMessageIter iter;
- DBusMessageIter sub;
- uint16_t value;
-
- if (!dbus_message_iter_init(msg, &iter))
- return btd_error_invalid_args(msg);
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_get_basic(&iter, &property);
- if (g_strcmp0("Interval", property) != 0)
- return btd_error_invalid_args(msg);
-
- if (!t->has_interval)
- return btd_error_not_available(msg);
-
- dbus_message_iter_next(&iter);
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_recurse(&iter, &sub);
-
- if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
- return btd_error_invalid_args(msg);
-
- dbus_message_iter_get_basic(&sub, &value);
-
- return write_attr_interval(t, msg, value);
-}
-
-static void enable_final_measurement(struct thermometer *t)
-{
- struct characteristic *ch;
- struct descriptor *desc;
- bt_uuid_t btuuid;
- uint8_t atval[2];
- char *msg;
-
- if (t->attrib == NULL)
- return;
-
- ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
- if (ch == NULL) {
- DBG("Temperature measurement characteristic not found");
- return;
- }
-
- bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
- desc = get_descriptor(ch, &btuuid);
- if (desc == NULL) {
- DBG("Client characteristic configuration descriptor not found");
- return;
- }
-
- atval[0] = 0x02;
- atval[1] = 0x00;
- msg = g_strdup("Enable final measurement");
- gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void enable_intermediate_measurement(struct thermometer *t)
-{
- struct characteristic *ch;
- struct descriptor *desc;
- bt_uuid_t btuuid;
- uint8_t atval[2];
- char *msg;
-
- if (t->attrib == NULL)
- return;
-
- ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
- if (ch == NULL) {
- DBG("Intermediate measurement characteristic not found");
- return;
- }
-
- bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
- desc = get_descriptor(ch, &btuuid);
- if (desc == NULL) {
- DBG("Client characteristic configuration descriptor not found");
- return;
- }
-
- atval[0] = 0x01;
- atval[1] = 0x00;
- msg = g_strdup("Enable intermediate measurement");
- gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void disable_final_measurement(struct thermometer *t)
-{
- struct characteristic *ch;
- struct descriptor *desc;
- bt_uuid_t btuuid;
- uint8_t atval[2];
- char *msg;
-
- if (t->attrib == NULL)
- return;
-
- ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
- if (ch == NULL) {
- DBG("Temperature measurement characteristic not found");
- return;
- }
-
- bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
- desc = get_descriptor(ch, &btuuid);
- if (desc == NULL) {
- DBG("Client characteristic configuration descriptor not found");
- return;
- }
-
- atval[0] = 0x00;
- atval[1] = 0x00;
- msg = g_strdup("Disable final measurement");
- gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void disable_intermediate_measurement(struct thermometer *t)
-{
- struct characteristic *ch;
- struct descriptor *desc;
- bt_uuid_t btuuid;
- uint8_t atval[2];
- char *msg;
-
- if (t->attrib == NULL)
- return;
-
- ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
- if (ch == NULL) {
- DBG("Intermediate measurement characteristic not found");
- return;
- }
-
- bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
- desc = get_descriptor(ch, &btuuid);
- if (desc == NULL) {
- DBG("Client characteristic configuration descriptor not found");
- return;
- }
-
- atval[0] = 0x00;
- atval[1] = 0x00;
- msg = g_strdup("Disable intermediate measurement");
- gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void remove_int_watcher(struct thermometer *t, struct watcher *w)
-{
- if (!g_slist_find(t->iwatchers, w))
- return;
-
- t->iwatchers = g_slist_remove(t->iwatchers, w);
-
- if (g_slist_length(t->iwatchers) == 0)
- disable_intermediate_measurement(t);
-}
-
-static void watcher_exit(DBusConnection *conn, void *user_data)
-{
- struct watcher *watcher = user_data;
- struct thermometer *t = watcher->t;
-
- DBG("Thermometer watcher %s disconnected", watcher->path);
-
- remove_int_watcher(t, watcher);
-
- t->fwatchers = g_slist_remove(t->fwatchers, watcher);
- g_dbus_remove_watch(watcher->t->conn, watcher->id);
-
- if (g_slist_length(t->fwatchers) == 0)
- disable_final_measurement(t);
-}
-
-static struct watcher *find_watcher(GSList *list, const char *sender,
- const char *path)
-{
- struct watcher *match;
- GSList *l;
-
- match = g_new0(struct watcher, 1);
- match->srv = g_strdup(sender);
- match->path = g_strdup(path);
-
- l = g_slist_find_custom(list, match, cmp_watcher);
- destroy_watcher(match);
-
- if (l != NULL)
- return l->data;
-
- return NULL;
-}
-
-static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *sender = dbus_message_get_sender(msg);
- struct thermometer *t = data;
- struct watcher *watcher;
- char *path;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- watcher = find_watcher(t->fwatchers, sender, path);
- if (watcher != NULL)
- return btd_error_already_exists(msg);
-
- DBG("Thermometer watcher %s registered", path);
-
- watcher = g_new0(struct watcher, 1);
- watcher->srv = g_strdup(sender);
- watcher->path = g_strdup(path);
- watcher->t = t;
- watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
- watcher, destroy_watcher);
-
- if (g_slist_length(t->fwatchers) == 0)
- enable_final_measurement(t);
-
- t->fwatchers = g_slist_prepend(t->fwatchers, watcher);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *sender = dbus_message_get_sender(msg);
- struct thermometer *t = data;
- struct watcher *watcher;
- char *path;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- watcher = find_watcher(t->fwatchers, sender, path);
- if (watcher == NULL)
- return btd_error_does_not_exist(msg);
-
- DBG("Thermometer watcher %s unregistered", path);
-
- remove_int_watcher(t, watcher);
-
- t->fwatchers = g_slist_remove(t->fwatchers, watcher);
- g_dbus_remove_watch(watcher->t->conn, watcher->id);
-
- if (g_slist_length(t->fwatchers) == 0)
- disable_final_measurement(t);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *enable_intermediate(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *sender = dbus_message_get_sender(msg);
- struct thermometer *t = data;
- struct watcher *watcher;
- char *path;
-
- if (!t->intermediate)
- return btd_error_not_supported(msg);
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- watcher = find_watcher(t->fwatchers, sender, path);
- if (watcher == NULL)
- return btd_error_does_not_exist(msg);
-
- if (find_watcher(t->iwatchers, sender, path))
- return btd_error_already_exists(msg);
-
- DBG("Intermediate measurement watcher %s registered", path);
-
- if (g_slist_length(t->iwatchers) == 0)
- enable_intermediate_measurement(t);
-
- t->iwatchers = g_slist_prepend(t->iwatchers, watcher);
-
- return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- const char *sender = dbus_message_get_sender(msg);
- struct thermometer *t = data;
- struct watcher *watcher;
- char *path;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
-
- watcher = find_watcher(t->iwatchers, sender, path);
- if (watcher == NULL)
- return btd_error_does_not_exist(msg);
-
- DBG("Intermediate measurement %s unregistered", path);
-
- remove_int_watcher(t, watcher);
-
- return dbus_message_new_method_return(msg);
-}
-
-static const GDBusMethodTable thermometer_methods[] = {
- { GDBUS_METHOD("GetProperties",
- NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
- get_properties) },
- { GDBUS_ASYNC_METHOD("SetProperty",
- GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
- set_property) },
- { GDBUS_METHOD("RegisterWatcher",
- GDBUS_ARGS({ "agent", "o" }), NULL,
- register_watcher) },
- { GDBUS_METHOD("UnregisterWatcher",
- GDBUS_ARGS({ "agent", "o" }), NULL,
- unregister_watcher) },
- { GDBUS_METHOD("EnableIntermediateMeasurement",
- GDBUS_ARGS({ "agent", "o" }), NULL,
- enable_intermediate) },
- { GDBUS_METHOD("DisableIntermediateMeasurement",
- GDBUS_ARGS({ "agent", "o" }), NULL,
- disable_intermediate) },
- { }
-};
-
-static const GDBusSignalTable thermometer_signals[] = {
- { GDBUS_SIGNAL("PropertyChanged",
- GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
- { }
-};
-
-static void update_watcher(gpointer data, gpointer user_data)
-{
- struct watcher *w = data;
- struct measurement *m = user_data;
- DBusConnection *conn = w->t->conn;
- DBusMessageIter iter;
- DBusMessageIter dict;
- DBusMessage *msg;
-
- msg = dbus_message_new_method_call(w->srv, w->path,
- "org.bluez.ThermometerWatcher",
- "MeasurementReceived");
- if (msg == NULL)
- return;
-
- dbus_message_iter_init_append(msg, &iter);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
- dict_append_entry(&dict, "Exponent", DBUS_TYPE_INT16, &m->exp);
- dict_append_entry(&dict, "Mantissa", DBUS_TYPE_INT32, &m->mant);
- dict_append_entry(&dict, "Unit", DBUS_TYPE_STRING, &m->unit);
-
- if (m->suptime)
- dict_append_entry(&dict, "Time", DBUS_TYPE_UINT64, &m->time);
-
- dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &m->type);
- dict_append_entry(&dict, "Measurement", DBUS_TYPE_STRING, &m->value);
-
- dbus_message_iter_close_container(&iter, &dict);
-
- dbus_message_set_no_reply(msg, TRUE);
- g_dbus_send_message(conn, msg);
-}
-
-static void recv_measurement(struct thermometer *t, struct measurement *m)
-{
- GSList *wlist;
-
- if (g_strcmp0(m->value, "Intermediate") == 0)
- wlist = t->iwatchers;
- else
- wlist = t->fwatchers;
-
- g_slist_foreach(wlist, update_watcher, m);
-}
-
-static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
- uint16_t len, gboolean final)
-{
- struct measurement m;
- const char *type;
- uint8_t flags;
- uint32_t raw;
-
- if (len < 4) {
- DBG("Mandatory flags are not provided");
- return;
- }
-
- flags = pdu[3];
- if (flags & TEMP_UNITS)
- m.unit = "Fahrenheit";
- else
- m.unit = "Celsius";
-
- if (len < 8) {
- DBG("Temperature measurement value is not provided");
- return;
- }
-
- raw = att_get_u32(&pdu[4]);
- m.mant = raw & 0x00FFFFFF;
- m.exp = ((int32_t) raw) >> 24;
-
- if (m.mant & 0x00800000) {
- /* convert to C2 negative value */
- m.mant = m.mant - FLOAT_MAX_MANTISSA;
- }
-
- if (flags & TEMP_TIME_STAMP) {
- struct tm ts;
- time_t time;
-
- if (len < 15) {
- DBG("Can't get time stamp value");
- return;
- }
-
- ts.tm_year = att_get_u16(&pdu[8]) - 1900;
- ts.tm_mon = pdu[10] - 1;
- ts.tm_mday = pdu[11];
- ts.tm_hour = pdu[12];
- ts.tm_min = pdu[13];
- ts.tm_sec = pdu[14];
- ts.tm_isdst = -1;
-
- time = mktime(&ts);
- m.time = (uint64_t) time;
- m.suptime = TRUE;
- } else
- m.suptime = FALSE;
-
- if (flags & TEMP_TYPE) {
- uint8_t index;
-
- if (m.suptime && len >= 16)
- index = 15;
- else if (!m.suptime && len >= 9)
- index = 9;
- else {
- DBG("Can't get temperature type");
- return;
- }
-
- type = temptype2str(pdu[index]);
- } else if (t->has_type)
- type = temptype2str(t->type);
- else
- type = NULL;
-
- m.type = type ? g_strdup(type) : NULL;
- m.value = final ? "Final" : "Intermediate";
-
- recv_measurement(t, &m);
- g_free(m.type);
-}
-
-static void proc_measurement_interval(struct thermometer *t, const uint8_t *pdu,
- uint16_t len)
-{
- uint16_t interval;
-
- if (len < 5) {
- DBG("Measurement interval value is not provided");
- return;
- }
-
- interval = att_get_u16(&pdu[3]);
-
- change_property(t, "Interval", &interval);
-}
-
-static void ind_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
- struct thermometer *t = user_data;
- const struct characteristic *ch;
- uint8_t opdu[ATT_MAX_MTU];
- uint16_t handle, olen;
- GSList *l;
-
- if (len < 3) {
- DBG("Bad pdu received");
- return;
- }
-
- handle = att_get_u16(&pdu[1]);
- l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
- if (l == NULL) {
- DBG("Unexpected handle: 0x%04x", handle);
- return;
- }
-
- ch = l->data;
-
- if (g_strcmp0(ch->attr.uuid, TEMPERATURE_MEASUREMENT_UUID) == 0)
- proc_measurement(t, pdu, len, TRUE);
- else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
- proc_measurement_interval(t, pdu, len);
-
- olen = enc_confirmation(opdu, sizeof(opdu));
-
- if (olen > 0)
- g_attrib_send(t->attrib, 0, opdu[0], opdu, olen, NULL, NULL,
- NULL);
-}
-
-static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
- struct thermometer *t = user_data;
- const struct characteristic *ch;
- uint16_t handle;
- GSList *l;
-
- if (len < 3) {
- DBG("Bad pdu received");
- return;
- }
-
- handle = att_get_u16(&pdu[1]);
- l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
- if (l == NULL) {
- DBG("Unexpected handle: 0x%04x", handle);
- return;
- }
-
- ch = l->data;
- if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0)
- proc_measurement(t, pdu, len, FALSE);
-}
-
-static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-{
- struct thermometer *t = user_data;
-
- t->attrib = g_attrib_ref(attrib);
-
- t->attindid = g_attrib_register(t->attrib, ATT_OP_HANDLE_IND,
- ind_handler, t, NULL);
- t->attnotid = g_attrib_register(t->attrib, ATT_OP_HANDLE_NOTIFY,
- notif_handler, t, NULL);
- gatt_discover_char(t->attrib, t->svc_range->start, t->svc_range->end,
- NULL, configure_thermometer_cb, t);
-}
-
-static void attio_disconnected_cb(gpointer user_data)
-{
- struct thermometer *t = user_data;
-
- DBG("GATT Disconnected");
-
- if (t->attindid > 0) {
- g_attrib_unregister(t->attrib, t->attindid);
- t->attindid = 0;
- }
-
- if (t->attnotid > 0) {
- g_attrib_unregister(t->attrib, t->attnotid);
- t->attnotid = 0;
- }
-
- g_attrib_unref(t->attrib);
- t->attrib = NULL;
-}
-
-int thermometer_register(DBusConnection *connection, struct btd_device *device,
- struct gatt_primary *tattr)
-{
- const gchar *path = device_get_path(device);
- struct thermometer *t;
-
- t = g_new0(struct thermometer, 1);
- t->conn = dbus_connection_ref(connection);
- t->dev = btd_device_ref(device);
- t->svc_range = g_new0(struct att_range, 1);
- t->svc_range->start = tattr->range.start;
- t->svc_range->end = tattr->range.end;
-
- if (!g_dbus_register_interface(t->conn, path, THERMOMETER_INTERFACE,
- thermometer_methods, thermometer_signals,
- NULL, t, destroy_thermometer)) {
- error("D-Bus failed to register %s interface",
- THERMOMETER_INTERFACE);
- destroy_thermometer(t);
- return -EIO;
- }
-
- thermometers = g_slist_prepend(thermometers, t);
-
- t->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
- attio_disconnected_cb, t);
- return 0;
-}
-
-void thermometer_unregister(struct btd_device *device)
-{
- struct thermometer *t;
- GSList *l;
-
- l = g_slist_find_custom(thermometers, device, cmp_device);
- if (l == NULL)
- return;
-
- t = l->data;
- thermometers = g_slist_remove(thermometers, t);
- g_dbus_unregister_interface(t->conn, device_get_path(t->dev),
- THERMOMETER_INTERFACE);
-}
diff --git a/thermometer/thermometer.h b/thermometer/thermometer.h
deleted file mode 100644
index 330503c..0000000
--- a/thermometer/thermometer.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- * 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
- *
- */
-
-int thermometer_register(DBusConnection *connection, struct btd_device *device,
- struct gatt_primary *tattr);
-void thermometer_unregister(struct btd_device *device);
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 21/21] time: move to the profiles folder
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (17 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 20/21] thermometer: " Gustavo Padovan
@ 2012-06-13 20:43 ` Gustavo Padovan
2012-06-14 9:22 ` [PATCH 00/21] BlueZ 5.0 patches Bastien Nocera
19 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-13 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
Makefile.am | 3 +-
profiles/time/main.c | 58 ++++++++++++++++++
profiles/time/server.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++
profiles/time/server.h | 26 ++++++++
time/main.c | 58 ------------------
time/server.c | 154 ------------------------------------------------
time/server.h | 26 --------
7 files changed, 240 insertions(+), 239 deletions(-)
create mode 100644 profiles/time/main.c
create mode 100644 profiles/time/server.c
create mode 100644 profiles/time/server.h
delete mode 100644 time/main.c
delete mode 100644 time/server.c
delete mode 100644 time/server.h
diff --git a/Makefile.am b/Makefile.am
index 631af43..9b05cf1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -226,7 +226,8 @@ builtin_sources += profiles/thermometer/main.c \
profiles/thermometer/thermometer.c \
profiles/alert/main.c profiles/alert/server.h \
profiles/alert/server.c \
- time/main.c time/server.h time/server.c \
+ profiles/time/main.c profiles/time/server.h \
+ profiles/time/server.c \
plugins/gatt-example.c \
profiles/proximity/main.c profiles/proximity/manager.h \
profiles/proximity/manager.c \
diff --git a/profiles/time/main.c b/profiles/time/main.c
new file mode 100644
index 0000000..d876725
--- /dev/null
+++ b/profiles/time/main.c
@@ -0,0 +1,58 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 <stdint.h>
+#include <glib.h>
+#include <errno.h>
+
+#include "plugin.h"
+#include "hcid.h"
+#include "log.h"
+#include "server.h"
+
+static int time_init(void)
+{
+ if (!main_opts.gatt_enabled) {
+ DBG("GATT is disabled");
+ return -ENOTSUP;
+ }
+
+ return time_server_init();
+}
+
+static void time_exit(void)
+{
+ if (!main_opts.gatt_enabled)
+ return;
+
+ time_server_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(time, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+ time_init, time_exit)
diff --git a/profiles/time/server.c b/profiles/time/server.c
new file mode 100644
index 0000000..13a7bbe
--- /dev/null
+++ b/profiles/time/server.c
@@ -0,0 +1,154 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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 <glib.h>
+#include <time.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+#include <adapter.h>
+
+#include "gattrib.h"
+#include "att.h"
+#include "gatt.h"
+#include "att-database.h"
+#include "attrib-server.h"
+#include "gatt-service.h"
+#include "log.h"
+#include "server.h"
+
+#define CURRENT_TIME_SVC_UUID 0x1805
+
+#define LOCAL_TIME_INFO_CHR_UUID 0x2A0F
+#define CT_TIME_CHR_UUID 0x2A2B
+
+static int encode_current_time(uint8_t value[10])
+{
+ struct timespec tp;
+ struct tm tm;
+
+ if (clock_gettime(CLOCK_REALTIME, &tp) == -1) {
+ int err = -errno;
+
+ error("clock_gettime: %s", strerror(-err));
+ return err;
+ }
+
+ if (localtime_r(&tp.tv_sec, &tm) == NULL) {
+ error("localtime_r() failed");
+ /* localtime_r() does not set errno */
+ return -EINVAL;
+ }
+
+ att_put_u16(1900 + tm.tm_year, &value[0]); /* Year */
+ value[2] = tm.tm_mon + 1; /* Month */
+ value[3] = tm.tm_mday; /* Day */
+ value[4] = tm.tm_hour; /* Hours */
+ value[5] = tm.tm_min; /* Minutes */
+ value[6] = tm.tm_sec; /* Seconds */
+ value[7] = tm.tm_wday == 0 ? 7 : tm.tm_wday; /* Day of Week */
+ /* From Time Profile spec: "The number of 1/256 fractions of a second."
+ * In 1s there are 256 fractions, in 1ns there are 256/10^9 fractions.
+ * To avoid integer overflow, we use the equivalent 1/3906250 ratio. */
+ value[8] = tp.tv_nsec / 3906250; /* Fractions256 */
+ value[9] = 0x00; /* Adjust Reason */
+
+ return 0;
+}
+
+static uint8_t current_time_read(struct attribute *a,
+ struct btd_device *device, gpointer user_data)
+{
+ uint8_t value[10];
+
+ if (encode_current_time(value) < 0)
+ return ATT_ECODE_IO;
+
+ /* FIXME: Provide the adapter in next function */
+ attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
+
+ return 0;
+}
+
+static uint8_t local_time_info_read(struct attribute *a,
+ struct btd_device *device, gpointer user_data)
+{
+ uint8_t value[2];
+
+ DBG("a=%p", a);
+
+ tzset();
+
+ /* FIXME: POSIX "daylight" variable only indicates whether there is DST
+ * for the local time or not. The offset is unknown. */
+ value[0] = daylight ? 0xff : 0x00;
+
+ /* Convert POSIX "timezone" (seconds West of GMT) to Time Profile
+ * format (offset from UTC in number of 15 minutes increments). */
+ value[1] = (uint8_t) (-1 * timezone / (60 * 15));
+
+ /* FIXME: Provide the adapter in next function */
+ attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
+
+ return 0;
+}
+
+static void register_current_time_service(void)
+{
+ bt_uuid_t uuid;
+
+ bt_uuid16_create(&uuid, CURRENT_TIME_SVC_UUID);
+
+ /* Current Time service */
+ /* FIXME: Provide the adapter in next function */
+ gatt_service_add(NULL, GATT_PRIM_SVC_UUID, &uuid,
+ /* CT Time characteristic */
+ GATT_OPT_CHR_UUID, CT_TIME_CHR_UUID,
+ GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
+ ATT_CHAR_PROPER_NOTIFY,
+ GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+ current_time_read, NULL,
+
+ /* Local Time Information characteristic */
+ GATT_OPT_CHR_UUID, LOCAL_TIME_INFO_CHR_UUID,
+ GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
+ GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+ local_time_info_read, NULL,
+
+ GATT_OPT_INVALID);
+}
+
+int time_server_init(void)
+{
+ register_current_time_service();
+
+ return 0;
+}
+
+void time_server_exit(void)
+{
+}
diff --git a/profiles/time/server.h b/profiles/time/server.h
new file mode 100644
index 0000000..621bf2b
--- /dev/null
+++ b/profiles/time/server.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * 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
+ *
+ */
+
+int time_server_init(void);
+void time_server_exit(void);
diff --git a/time/main.c b/time/main.c
deleted file mode 100644
index d876725..0000000
--- a/time/main.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 Nokia Corporation
- * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 <stdint.h>
-#include <glib.h>
-#include <errno.h>
-
-#include "plugin.h"
-#include "hcid.h"
-#include "log.h"
-#include "server.h"
-
-static int time_init(void)
-{
- if (!main_opts.gatt_enabled) {
- DBG("GATT is disabled");
- return -ENOTSUP;
- }
-
- return time_server_init();
-}
-
-static void time_exit(void)
-{
- if (!main_opts.gatt_enabled)
- return;
-
- time_server_exit();
-}
-
-BLUETOOTH_PLUGIN_DEFINE(time, VERSION,
- BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
- time_init, time_exit)
diff --git a/time/server.c b/time/server.c
deleted file mode 100644
index 13a7bbe..0000000
--- a/time/server.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 Nokia Corporation
- * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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 <glib.h>
-#include <time.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-#include <adapter.h>
-
-#include "gattrib.h"
-#include "att.h"
-#include "gatt.h"
-#include "att-database.h"
-#include "attrib-server.h"
-#include "gatt-service.h"
-#include "log.h"
-#include "server.h"
-
-#define CURRENT_TIME_SVC_UUID 0x1805
-
-#define LOCAL_TIME_INFO_CHR_UUID 0x2A0F
-#define CT_TIME_CHR_UUID 0x2A2B
-
-static int encode_current_time(uint8_t value[10])
-{
- struct timespec tp;
- struct tm tm;
-
- if (clock_gettime(CLOCK_REALTIME, &tp) == -1) {
- int err = -errno;
-
- error("clock_gettime: %s", strerror(-err));
- return err;
- }
-
- if (localtime_r(&tp.tv_sec, &tm) == NULL) {
- error("localtime_r() failed");
- /* localtime_r() does not set errno */
- return -EINVAL;
- }
-
- att_put_u16(1900 + tm.tm_year, &value[0]); /* Year */
- value[2] = tm.tm_mon + 1; /* Month */
- value[3] = tm.tm_mday; /* Day */
- value[4] = tm.tm_hour; /* Hours */
- value[5] = tm.tm_min; /* Minutes */
- value[6] = tm.tm_sec; /* Seconds */
- value[7] = tm.tm_wday == 0 ? 7 : tm.tm_wday; /* Day of Week */
- /* From Time Profile spec: "The number of 1/256 fractions of a second."
- * In 1s there are 256 fractions, in 1ns there are 256/10^9 fractions.
- * To avoid integer overflow, we use the equivalent 1/3906250 ratio. */
- value[8] = tp.tv_nsec / 3906250; /* Fractions256 */
- value[9] = 0x00; /* Adjust Reason */
-
- return 0;
-}
-
-static uint8_t current_time_read(struct attribute *a,
- struct btd_device *device, gpointer user_data)
-{
- uint8_t value[10];
-
- if (encode_current_time(value) < 0)
- return ATT_ECODE_IO;
-
- /* FIXME: Provide the adapter in next function */
- attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
-
- return 0;
-}
-
-static uint8_t local_time_info_read(struct attribute *a,
- struct btd_device *device, gpointer user_data)
-{
- uint8_t value[2];
-
- DBG("a=%p", a);
-
- tzset();
-
- /* FIXME: POSIX "daylight" variable only indicates whether there is DST
- * for the local time or not. The offset is unknown. */
- value[0] = daylight ? 0xff : 0x00;
-
- /* Convert POSIX "timezone" (seconds West of GMT) to Time Profile
- * format (offset from UTC in number of 15 minutes increments). */
- value[1] = (uint8_t) (-1 * timezone / (60 * 15));
-
- /* FIXME: Provide the adapter in next function */
- attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
-
- return 0;
-}
-
-static void register_current_time_service(void)
-{
- bt_uuid_t uuid;
-
- bt_uuid16_create(&uuid, CURRENT_TIME_SVC_UUID);
-
- /* Current Time service */
- /* FIXME: Provide the adapter in next function */
- gatt_service_add(NULL, GATT_PRIM_SVC_UUID, &uuid,
- /* CT Time characteristic */
- GATT_OPT_CHR_UUID, CT_TIME_CHR_UUID,
- GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
- ATT_CHAR_PROPER_NOTIFY,
- GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
- current_time_read, NULL,
-
- /* Local Time Information characteristic */
- GATT_OPT_CHR_UUID, LOCAL_TIME_INFO_CHR_UUID,
- GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
- GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
- local_time_info_read, NULL,
-
- GATT_OPT_INVALID);
-}
-
-int time_server_init(void)
-{
- register_current_time_service();
-
- return 0;
-}
-
-void time_server_exit(void)
-{
-}
diff --git a/time/server.h b/time/server.h
deleted file mode 100644
index 621bf2b..0000000
--- a/time/server.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 Nokia Corporation
- * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- * 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
- *
- */
-
-int time_server_init(void);
-void time_server_exit(void);
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 03/21] headset: remove deprecated DBus methods
2012-06-13 20:43 ` [PATCH 03/21] headset: remove deprecated DBus methods Gustavo Padovan
@ 2012-06-14 7:43 ` Chanyeol Park
2012-06-14 8:14 ` Luiz Augusto von Dentz
2012-06-14 14:07 ` [PATCH -v2 " Gustavo Padovan
1 sibling, 1 reply; 29+ messages in thread
From: Chanyeol Park @ 2012-06-14 7:43 UTC (permalink / raw)
To: Gustavo Padovan; +Cc: linux-bluetooth, Gustavo Padovan
Hi
On 2012년 06월 14일 05:43, Gustavo Padovan wrote:
> From: Gustavo Padovan<gustavo.padovan@collabora.co.uk>
>
> ---
> audio/headset.c | 151 -----------------------------------------------------
> doc/audio-api.txt | 28 ----------
> 2 files changed, 179 deletions(-)
>
> diff --git a/audio/headset.c b/audio/headset.c
> index 729e4dc..3ce7eb9 100644
> --- a/audio/headset.c
> +++ b/audio/headset.c
> @@ -1673,26 +1673,6 @@ static DBusMessage *hs_stop(DBusConnection *conn, DBusMessage *msg,
> return reply;
> }
>
> -static DBusMessage *hs_is_playing(DBusConnection *conn, DBusMessage *msg,
> - void *data)
> -{
> - struct audio_device *device = data;
> - struct headset *hs = device->headset;
> - DBusMessage *reply;
> - dbus_bool_t playing;
> -
> - reply = dbus_message_new_method_return(msg);
> - if (!reply)
> - return NULL;
> -
> - playing = (hs->state == HEADSET_STATE_PLAYING);
> -
> - dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN,&playing,
> - DBUS_TYPE_INVALID);
> -
> - return reply;
> -}
> -
> static DBusMessage *hs_disconnect(DBusConnection *conn, DBusMessage *msg,
> void *data)
> {
> @@ -1816,95 +1796,6 @@ static DBusMessage *hs_cancel_call(DBusConnection *conn,
> return reply;
> }
>
> -static DBusMessage *hs_play(DBusConnection *conn, DBusMessage *msg,
> - void *data)
> -{
> - struct audio_device *device = data;
> - struct headset *hs = device->headset;
> - int err;
> -
> - if (sco_hci) {
> - error("Refusing Headset.Play() because SCO HCI routing "
> - "is enabled");
> - return btd_error_not_available(msg);
> - }
> -
> - switch (hs->state) {
> - case HEADSET_STATE_DISCONNECTED:
> - case HEADSET_STATE_CONNECTING:
> - return btd_error_not_connected(msg);
> - case HEADSET_STATE_PLAY_IN_PROGRESS:
> - if (hs->pending&& hs->pending->msg == NULL) {
> - hs->pending->msg = dbus_message_ref(msg);
> - return NULL;
> - }
> - return btd_error_busy(msg);
> - case HEADSET_STATE_PLAYING:
> - return btd_error_already_connected(msg);
> - case HEADSET_STATE_CONNECTED:
> - default:
> - break;
> - }
> -
> - err = sco_connect(device, NULL, NULL, NULL);
> - if (err< 0)
> - return btd_error_failed(msg, strerror(-err));
> -
> - hs->pending->msg = dbus_message_ref(msg);
> -
> - return NULL;
> -}
> -
> -static DBusMessage *hs_get_speaker_gain(DBusConnection *conn,
> - DBusMessage *msg,
> - void *data)
> -{
> - struct audio_device *device = data;
> - struct headset *hs = device->headset;
> - struct headset_slc *slc = hs->slc;
> - DBusMessage *reply;
> - dbus_uint16_t gain;
> -
> - if (hs->state< HEADSET_STATE_CONNECTED)
> - return btd_error_not_available(msg);
> -
> - reply = dbus_message_new_method_return(msg);
> - if (!reply)
> - return NULL;
> -
> - gain = (dbus_uint16_t) slc->sp_gain;
> -
> - dbus_message_append_args(reply, DBUS_TYPE_UINT16,&gain,
> - DBUS_TYPE_INVALID);
> -
> - return reply;
> -}
> -
> -static DBusMessage *hs_get_mic_gain(DBusConnection *conn,
> - DBusMessage *msg,
> - void *data)
> -{
> - struct audio_device *device = data;
> - struct headset *hs = device->headset;
> - struct headset_slc *slc = hs->slc;
> - DBusMessage *reply;
> - dbus_uint16_t gain;
> -
> - if (hs->state< HEADSET_STATE_CONNECTED || slc == NULL)
> - return btd_error_not_available(msg);
> -
> - reply = dbus_message_new_method_return(msg);
> - if (!reply)
> - return NULL;
> -
> - gain = (dbus_uint16_t) slc->mic_gain;
> -
> - dbus_message_append_args(reply, DBUS_TYPE_UINT16,&gain,
> - DBUS_TYPE_INVALID);
> -
> - return reply;
> -}
> -
> static DBusMessage *hs_set_gain(DBusConnection *conn,
> DBusMessage *msg,
> void *data, uint16_t gain,
> @@ -1937,32 +1828,6 @@ static DBusMessage *hs_set_gain(DBusConnection *conn,
> return reply;
> }
>
> -static DBusMessage *hs_set_speaker_gain(DBusConnection *conn,
> - DBusMessage *msg,
> - void *data)
> -{
> - uint16_t gain;
> -
> - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16,&gain,
> - DBUS_TYPE_INVALID))
> - return NULL;
> -
> - return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_SPEAKER);
> -}
> -
> -static DBusMessage *hs_set_mic_gain(DBusConnection *conn,
> - DBusMessage *msg,
> - void *data)
> -{
> - uint16_t gain;
> -
> - if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16,&gain,
> - DBUS_TYPE_INVALID))
> - return NULL;
> -
> - return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_MICROPHONE);
> -}
> -
> static DBusMessage *hs_get_properties(DBusConnection *conn,
> DBusMessage *msg, void *data)
> {
> @@ -2065,23 +1930,7 @@ static const GDBusMethodTable headset_methods[] = {
> hs_is_connected) },
> { GDBUS_METHOD("IndicateCall", NULL, NULL, hs_ring) },
> { GDBUS_METHOD("CancelCall", NULL, NULL, hs_cancel_call) },
> - { GDBUS_DEPRECATED_ASYNC_METHOD("Play", NULL, NULL, hs_play) },
> { GDBUS_METHOD("Stop", NULL, NULL, hs_stop) },
> - { GDBUS_DEPRECATED_METHOD("IsPlaying",
> - NULL, GDBUS_ARGS({ "playing", "b" }),
> - hs_is_playing) },
> - { GDBUS_DEPRECATED_METHOD("GetSpeakerGain",
> - NULL, GDBUS_ARGS({ "gain", "q" }),
> - hs_get_speaker_gain) },
> - { GDBUS_DEPRECATED_METHOD("GetMicrophoneGain",
> - NULL, GDBUS_ARGS({ "gain", "q" }),
> - hs_get_mic_gain) },
> - { GDBUS_DEPRECATED_METHOD("SetSpeakerGain",
> - GDBUS_ARGS({ "gain", "q" }), NULL,
> - hs_set_speaker_gain) },
> - { GDBUS_DEPRECATED_METHOD("SetMicrophoneGain",
> - GDBUS_ARGS({ "gain", "q" }), NULL,
> - hs_set_mic_gain) },
> { GDBUS_METHOD("GetProperties",
> NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
> hs_get_properties) },
> diff --git a/doc/audio-api.txt b/doc/audio-api.txt
> index 02291fd..dc5c811 100644
> --- a/doc/audio-api.txt
> +++ b/doc/audio-api.txt
> @@ -66,11 +66,6 @@ Methods void Connect()
> Disconnect from the HSP/HFP service on the remote
> device.
>
> - boolean IsConnected() {deprecated}
> -
> - Returns TRUE if there is a active connection to the
> - HSP/HFP connection on the remote device.
> -
> void IndicateCall()
>
> Indicate an incoming call on the headset
> @@ -89,29 +84,6 @@ Methods void Connect()
>
> Close the audio connection.
>
> - boolean IsPlaying() {deprecated}
> -
> - Returns true if an audio connection to the headset
> - is active.
> -
> - uint16 GetSpeakerGain() {deprecated}
> -
> - Returns the current speaker gain if available,
> - otherwise returns the error NotAvailable.
> -
> - uint16 GetMicrophoneGain() {deprecated}
> -
> - Returns the current microphone gain if available,
> - otherwise returns the error NotAvailable.
> -
> - void SetSpeakerGain(uint16 gain) {deprecated}
> -
> - Changes the current speaker gain if possible.
> -
> - void SetMicrophoneGain(uint16 gain) {deprecated}
> -
> - Changes the current speaker gain if possible.
> -
> dict GetProperties()
>
> Returns all properties for the interface. See the
If you remove these APIs, could you guide me how to use SCO open officially?
Currently we don't use PulseAudio HFP modules.
BR
Chanyeol Park.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 03/21] headset: remove deprecated DBus methods
2012-06-14 7:43 ` Chanyeol Park
@ 2012-06-14 8:14 ` Luiz Augusto von Dentz
0 siblings, 0 replies; 29+ messages in thread
From: Luiz Augusto von Dentz @ 2012-06-14 8:14 UTC (permalink / raw)
To: Chanyeol Park; +Cc: Gustavo Padovan, linux-bluetooth, Gustavo Padovan
Hi Chanyel,
On Thu, Jun 14, 2012 at 10:43 AM, Chanyeol Park
<chanyeol.park@samsung.com> wrote:
> If you remove these APIs, could you guide me how to use SCO open officially?
> Currently we don't use PulseAudio HFP modules.
Via org.bluez.MediaTransport.Acquire, see doc/media-api.txt for more details.
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 00/21] BlueZ 5.0 patches
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
` (18 preceding siblings ...)
2012-06-13 20:43 ` [PATCH 21/21] time: " Gustavo Padovan
@ 2012-06-14 9:22 ` Bastien Nocera
2012-06-14 12:03 ` Anderson Lizardo
` (2 more replies)
19 siblings, 3 replies; 29+ messages in thread
From: Bastien Nocera @ 2012-06-14 9:22 UTC (permalink / raw)
To: Gustavo Padovan; +Cc: linux-bluetooth, Gustavo Padovan
On Wed, 2012-06-13 at 17:43 -0300, Gustavo Padovan wrote:
>
> remove compat daemons
Seeing as I can't find 01/21 on the mailing-list (too big?).
> compat/hidd.1 | 41 -
> compat/hidd.c | 848 --------
We need something to replace hidd --show, for debugging purposes.
> compat/fakehid.c | 669 ------
Is there something to replace the support for those devices? Nobody
seems to have added the support to input/fakehid.c which would be the
logical place.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 00/21] BlueZ 5.0 patches
2012-06-14 9:22 ` [PATCH 00/21] BlueZ 5.0 patches Bastien Nocera
@ 2012-06-14 12:03 ` Anderson Lizardo
2012-06-14 13:02 ` Szymon Janc
2012-06-14 12:18 ` Johan Hedberg
2012-06-14 13:34 ` Gustavo Padovan
2 siblings, 1 reply; 29+ messages in thread
From: Anderson Lizardo @ 2012-06-14 12:03 UTC (permalink / raw)
To: Bastien Nocera; +Cc: Gustavo Padovan, linux-bluetooth, Gustavo Padovan
Hi,
On Thu, Jun 14, 2012 at 5:22 AM, Bastien Nocera <hadess@hadess.net> wrote:
> On Wed, 2012-06-13 at 17:43 -0300, Gustavo Padovan wrote:
>>
>> remove compat daemons
>
> Seeing as I can't find 01/21 on the mailing-list (too big?).
19/21 also seems to be missing.
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 00/21] BlueZ 5.0 patches
2012-06-14 9:22 ` [PATCH 00/21] BlueZ 5.0 patches Bastien Nocera
2012-06-14 12:03 ` Anderson Lizardo
@ 2012-06-14 12:18 ` Johan Hedberg
2012-06-14 13:34 ` Gustavo Padovan
2 siblings, 0 replies; 29+ messages in thread
From: Johan Hedberg @ 2012-06-14 12:18 UTC (permalink / raw)
To: Bastien Nocera; +Cc: Gustavo Padovan, linux-bluetooth, Gustavo Padovan
Hi Bastien,
On Thu, Jun 14, 2012, Bastien Nocera wrote:
> > compat/hidd.1 | 41 -
> > compat/hidd.c | 848 --------
>
> We need something to replace hidd --show, for debugging purposes.
All that does is call a simple ioctl and print its result, requiring
maybe 10 lines of code or so. What we could do is add a small tool under
tools/ that can do the same task.
> > compat/fakehid.c | 669 ------
>
> Is there something to replace the support for those devices? Nobody
> seems to have added the support to input/fakehid.c which would be the
> logical place.
Yep, seems like the logical place to me too. Do we have any actual
users/developers of this device that would be willing to step up to do
this code merge and test that everything still works?
Johan
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 00/21] BlueZ 5.0 patches
2012-06-14 12:03 ` Anderson Lizardo
@ 2012-06-14 13:02 ` Szymon Janc
0 siblings, 0 replies; 29+ messages in thread
From: Szymon Janc @ 2012-06-14 13:02 UTC (permalink / raw)
To: Anderson Lizardo
Cc: Bastien Nocera, Gustavo Padovan, linux-bluetooth@vger.kernel.org,
Gustavo Padovan
Hi,
> On Thu, Jun 14, 2012 at 5:22 AM, Bastien Nocera <hadess@hadess.net> wrote:
> > On Wed, 2012-06-13 at 17:43 -0300, Gustavo Padovan wrote:
> >>
> >> remove compat daemons
> >
> > Seeing as I can't find 01/21 on the mailing-list (too big?).
>
> 19/21 also seems to be missing.
Maybe use -M switch for git format-patch so that it will detect renames?
Patches should be smaller.
--
Szymon Janc
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 00/21] BlueZ 5.0 patches
2012-06-14 9:22 ` [PATCH 00/21] BlueZ 5.0 patches Bastien Nocera
2012-06-14 12:03 ` Anderson Lizardo
2012-06-14 12:18 ` Johan Hedberg
@ 2012-06-14 13:34 ` Gustavo Padovan
2 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-14 13:34 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-bluetooth, Gustavo Padovan
Hi Bastien,
* Bastien Nocera <hadess@hadess.net> [2012-06-14 10:22:27 +0100]:
> On Wed, 2012-06-13 at 17:43 -0300, Gustavo Padovan wrote:
> >
> > remove compat daemons
>
> Seeing as I can't find 01/21 on the mailing-list (too big?).
Yes, too big:
http://littlechina.org/code/cgit/padovan/bluez/commit/?h=bluez5&id=2c8138a58740cb6b7dd49ad0132d51c8d8aa6c38
Gustavo
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 19/21] proximity: move to the profiles folder
2012-06-13 20:43 ` [PATCH 18/21] deviceinfo: move to profiles folder Gustavo Padovan
@ 2012-06-14 13:49 ` Gustavo Padovan
0 siblings, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-14 13:49 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
Makefile.am | 15 ++++++++++-----
{proximity => profiles/proximity}/immalert.c | 0
{proximity => profiles/proximity}/immalert.h | 0
{proximity => profiles/proximity}/linkloss.c | 0
{proximity => profiles/proximity}/linkloss.h | 0
{proximity => profiles/proximity}/main.c | 0
{proximity => profiles/proximity}/manager.c | 0
{proximity => profiles/proximity}/manager.h | 0
{proximity => profiles/proximity}/monitor.c | 0
{proximity => profiles/proximity}/monitor.h | 0
{proximity => profiles/proximity}/proximity.conf | 0
{proximity => profiles/proximity}/reporter.c | 0
{proximity => profiles/proximity}/reporter.h | 0
13 files changed, 10 insertions(+), 5 deletions(-)
rename {proximity => profiles/proximity}/immalert.c (100%)
rename {proximity => profiles/proximity}/immalert.h (100%)
rename {proximity => profiles/proximity}/linkloss.c (100%)
rename {proximity => profiles/proximity}/linkloss.h (100%)
rename {proximity => profiles/proximity}/main.c (100%)
rename {proximity => profiles/proximity}/manager.c (100%)
rename {proximity => profiles/proximity}/manager.h (100%)
rename {proximity => profiles/proximity}/monitor.c (100%)
rename {proximity => profiles/proximity}/monitor.h (100%)
rename {proximity => profiles/proximity}/proximity.conf (100%)
rename {proximity => profiles/proximity}/reporter.c (100%)
rename {proximity => profiles/proximity}/reporter.h (100%)
diff --git a/Makefile.am b/Makefile.am
index c239433..86c440d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -226,11 +226,16 @@ builtin_sources += thermometer/main.c \
profiles/alert/server.c \
time/main.c time/server.h time/server.c \
plugins/gatt-example.c \
- proximity/main.c proximity/manager.h proximity/manager.c \
- proximity/monitor.h proximity/monitor.c \
- proximity/reporter.h proximity/reporter.c \
- proximity/linkloss.h proximity/linkloss.c \
- proximity/immalert.h proximity/immalert.c \
+ profiles/proximity/main.c profiles/proximity/manager.h \
+ profiles/proximity/manager.c \
+ profiles/proximity/monitor.h \
+ profiles/proximity/monitor.c \
+ profiles/proximity/reporter.h \
+ profiles/proximity/reporter.c \
+ profiles/proximity/linkloss.h \
+ profiles/proximity/linkloss.c \
+ profiles/proximity/immalert.h \
+ profiles/proximity/immalert.c \
profiles/deviceinfo/main.c \
profiles/deviceinfo/manager.h \
profiles/deviceinfo/manager.c \
diff --git a/proximity/immalert.c b/profiles/proximity/immalert.c
similarity index 100%
rename from proximity/immalert.c
rename to profiles/proximity/immalert.c
diff --git a/proximity/immalert.h b/profiles/proximity/immalert.h
similarity index 100%
rename from proximity/immalert.h
rename to profiles/proximity/immalert.h
diff --git a/proximity/linkloss.c b/profiles/proximity/linkloss.c
similarity index 100%
rename from proximity/linkloss.c
rename to profiles/proximity/linkloss.c
diff --git a/proximity/linkloss.h b/profiles/proximity/linkloss.h
similarity index 100%
rename from proximity/linkloss.h
rename to profiles/proximity/linkloss.h
diff --git a/proximity/main.c b/profiles/proximity/main.c
similarity index 100%
rename from proximity/main.c
rename to profiles/proximity/main.c
diff --git a/proximity/manager.c b/profiles/proximity/manager.c
similarity index 100%
rename from proximity/manager.c
rename to profiles/proximity/manager.c
diff --git a/proximity/manager.h b/profiles/proximity/manager.h
similarity index 100%
rename from proximity/manager.h
rename to profiles/proximity/manager.h
diff --git a/proximity/monitor.c b/profiles/proximity/monitor.c
similarity index 100%
rename from proximity/monitor.c
rename to profiles/proximity/monitor.c
diff --git a/proximity/monitor.h b/profiles/proximity/monitor.h
similarity index 100%
rename from proximity/monitor.h
rename to profiles/proximity/monitor.h
diff --git a/proximity/proximity.conf b/profiles/proximity/proximity.conf
similarity index 100%
rename from proximity/proximity.conf
rename to profiles/proximity/proximity.conf
diff --git a/proximity/reporter.c b/profiles/proximity/reporter.c
similarity index 100%
rename from proximity/reporter.c
rename to profiles/proximity/reporter.c
diff --git a/proximity/reporter.h b/profiles/proximity/reporter.h
similarity index 100%
rename from proximity/reporter.h
rename to profiles/proximity/reporter.h
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH -v2 03/21] headset: remove deprecated DBus methods
2012-06-13 20:43 ` [PATCH 03/21] headset: remove deprecated DBus methods Gustavo Padovan
2012-06-14 7:43 ` Chanyeol Park
@ 2012-06-14 14:07 ` Gustavo Padovan
1 sibling, 0 replies; 29+ messages in thread
From: Gustavo Padovan @ 2012-06-14 14:07 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
v2: remove also play call from test-telephony
audio/headset.c | 151 ---------------------------------------------------
doc/audio-api.txt | 28 ----------
test/test-telephony | 12 ----
3 files changed, 191 deletions(-)
diff --git a/audio/headset.c b/audio/headset.c
index 729e4dc..3ce7eb9 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -1673,26 +1673,6 @@ static DBusMessage *hs_stop(DBusConnection *conn, DBusMessage *msg,
return reply;
}
-static DBusMessage *hs_is_playing(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- DBusMessage *reply;
- dbus_bool_t playing;
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- playing = (hs->state == HEADSET_STATE_PLAYING);
-
- dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
static DBusMessage *hs_disconnect(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -1816,95 +1796,6 @@ static DBusMessage *hs_cancel_call(DBusConnection *conn,
return reply;
}
-static DBusMessage *hs_play(DBusConnection *conn, DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- int err;
-
- if (sco_hci) {
- error("Refusing Headset.Play() because SCO HCI routing "
- "is enabled");
- return btd_error_not_available(msg);
- }
-
- switch (hs->state) {
- case HEADSET_STATE_DISCONNECTED:
- case HEADSET_STATE_CONNECTING:
- return btd_error_not_connected(msg);
- case HEADSET_STATE_PLAY_IN_PROGRESS:
- if (hs->pending && hs->pending->msg == NULL) {
- hs->pending->msg = dbus_message_ref(msg);
- return NULL;
- }
- return btd_error_busy(msg);
- case HEADSET_STATE_PLAYING:
- return btd_error_already_connected(msg);
- case HEADSET_STATE_CONNECTED:
- default:
- break;
- }
-
- err = sco_connect(device, NULL, NULL, NULL);
- if (err < 0)
- return btd_error_failed(msg, strerror(-err));
-
- hs->pending->msg = dbus_message_ref(msg);
-
- return NULL;
-}
-
-static DBusMessage *hs_get_speaker_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- DBusMessage *reply;
- dbus_uint16_t gain;
-
- if (hs->state < HEADSET_STATE_CONNECTED)
- return btd_error_not_available(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- gain = (dbus_uint16_t) slc->sp_gain;
-
- dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
-static DBusMessage *hs_get_mic_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- struct audio_device *device = data;
- struct headset *hs = device->headset;
- struct headset_slc *slc = hs->slc;
- DBusMessage *reply;
- dbus_uint16_t gain;
-
- if (hs->state < HEADSET_STATE_CONNECTED || slc == NULL)
- return btd_error_not_available(msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return NULL;
-
- gain = (dbus_uint16_t) slc->mic_gain;
-
- dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID);
-
- return reply;
-}
-
static DBusMessage *hs_set_gain(DBusConnection *conn,
DBusMessage *msg,
void *data, uint16_t gain,
@@ -1937,32 +1828,6 @@ static DBusMessage *hs_set_gain(DBusConnection *conn,
return reply;
}
-static DBusMessage *hs_set_speaker_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- uint16_t gain;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID))
- return NULL;
-
- return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_SPEAKER);
-}
-
-static DBusMessage *hs_set_mic_gain(DBusConnection *conn,
- DBusMessage *msg,
- void *data)
-{
- uint16_t gain;
-
- if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
- DBUS_TYPE_INVALID))
- return NULL;
-
- return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_MICROPHONE);
-}
-
static DBusMessage *hs_get_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -2065,23 +1930,7 @@ static const GDBusMethodTable headset_methods[] = {
hs_is_connected) },
{ GDBUS_METHOD("IndicateCall", NULL, NULL, hs_ring) },
{ GDBUS_METHOD("CancelCall", NULL, NULL, hs_cancel_call) },
- { GDBUS_DEPRECATED_ASYNC_METHOD("Play", NULL, NULL, hs_play) },
{ GDBUS_METHOD("Stop", NULL, NULL, hs_stop) },
- { GDBUS_DEPRECATED_METHOD("IsPlaying",
- NULL, GDBUS_ARGS({ "playing", "b" }),
- hs_is_playing) },
- { GDBUS_DEPRECATED_METHOD("GetSpeakerGain",
- NULL, GDBUS_ARGS({ "gain", "q" }),
- hs_get_speaker_gain) },
- { GDBUS_DEPRECATED_METHOD("GetMicrophoneGain",
- NULL, GDBUS_ARGS({ "gain", "q" }),
- hs_get_mic_gain) },
- { GDBUS_DEPRECATED_METHOD("SetSpeakerGain",
- GDBUS_ARGS({ "gain", "q" }), NULL,
- hs_set_speaker_gain) },
- { GDBUS_DEPRECATED_METHOD("SetMicrophoneGain",
- GDBUS_ARGS({ "gain", "q" }), NULL,
- hs_set_mic_gain) },
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
hs_get_properties) },
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index 02291fd..dc5c811 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -66,11 +66,6 @@ Methods void Connect()
Disconnect from the HSP/HFP service on the remote
device.
- boolean IsConnected() {deprecated}
-
- Returns TRUE if there is a active connection to the
- HSP/HFP connection on the remote device.
-
void IndicateCall()
Indicate an incoming call on the headset
@@ -89,29 +84,6 @@ Methods void Connect()
Close the audio connection.
- boolean IsPlaying() {deprecated}
-
- Returns true if an audio connection to the headset
- is active.
-
- uint16 GetSpeakerGain() {deprecated}
-
- Returns the current speaker gain if available,
- otherwise returns the error NotAvailable.
-
- uint16 GetMicrophoneGain() {deprecated}
-
- Returns the current microphone gain if available,
- otherwise returns the error NotAvailable.
-
- void SetSpeakerGain(uint16 gain) {deprecated}
-
- Changes the current speaker gain if possible.
-
- void SetMicrophoneGain(uint16 gain) {deprecated}
-
- Changes the current speaker gain if possible.
-
dict GetProperties()
Returns all properties for the interface. See the
diff --git a/test/test-telephony b/test/test-telephony
index 5ef0ac8..429f422 100755
--- a/test/test-telephony
+++ b/test/test-telephony
@@ -42,7 +42,6 @@ if len(args) < 1:
subscriber <number>
speakergain <bdaddr> [level]
microphonegain <bdaddr> [level]
- play <bdaddr>
stop <bdaddr>
""" % sys.argv[0]
sys.exit(1)
@@ -97,17 +96,6 @@ if args[0] == "microphonegain":
sys.exit(0)
-if args[0] == "play":
- if len(args) < 2:
- print "Need device address parameter"
- sys.exit(1)
- device = adapter.FindDevice(args[1])
- headset = dbus.Interface(bus.get_object("org.bluez", device),
- "org.bluez.Headset")
- headset.Play()
-
- sys.exit(0)
-
if args[0] == "stop":
if len(args) < 2:
print "Need device address parameter"
--
1.7.10.2
^ permalink raw reply related [flat|nested] 29+ messages in thread
end of thread, other threads:[~2012-06-14 14:07 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-13 20:43 [PATCH 00/21] BlueZ 5.0 patches Gustavo Padovan
2012-06-13 20:43 ` [PATCH 02/21] remove the hciops plugin Gustavo Padovan
2012-06-13 20:43 ` [PATCH 03/21] headset: remove deprecated DBus methods Gustavo Padovan
2012-06-14 7:43 ` Chanyeol Park
2012-06-14 8:14 ` Luiz Augusto von Dentz
2012-06-14 14:07 ` [PATCH -v2 " Gustavo Padovan
2012-06-13 20:43 ` [PATCH 04/21] sink: remove deprecated DBus method Gustavo Padovan
2012-06-13 20:43 ` [PATCH 05/21] adapter: remove deprecated ListDevices() method Gustavo Padovan
2012-06-13 20:43 ` [PATCH 06/21] manager: remove deprecated ListAdapters() method Gustavo Padovan
2012-06-13 20:43 ` [PATCH 07/21] adapter: remove btd_adapter_encrypt_link() Gustavo Padovan
2012-06-13 20:43 ` [PATCH 08/21] adapter_ops: remove disable_cod_cache Gustavo Padovan
2012-06-13 20:43 ` [PATCH 09/21] manager: remove unused manager_add_adapter() Gustavo Padovan
2012-06-13 20:43 ` [PATCH 10/21] adapter: make restore powered work again Gustavo Padovan
2012-06-13 20:43 ` [PATCH 11/21] serial: remove SerialProxy interface Gustavo Padovan
2012-06-13 20:43 ` [PATCH 12/21] serial: remove unneeded headers include Gustavo Padovan
2012-06-13 20:43 ` [PATCH 13/21] input: remove unneeded header inclusions Gustavo Padovan
2012-06-13 20:43 ` [PATCH 14/21] serial: remove old way to connect to a serial port Gustavo Padovan
2012-06-13 20:43 ` [PATCH 15/21] emulator: move it to the tools folder Gustavo Padovan
2012-06-13 20:43 ` [PATCH 16/21] btmgmt: move to " Gustavo Padovan
2012-06-13 20:43 ` [PATCH 17/21] alert: move alert to profiles dir Gustavo Padovan
2012-06-13 20:43 ` [PATCH 18/21] deviceinfo: move to profiles folder Gustavo Padovan
2012-06-14 13:49 ` [PATCH 19/21] proximity: move to the " Gustavo Padovan
2012-06-13 20:43 ` [PATCH 20/21] thermometer: " Gustavo Padovan
2012-06-13 20:43 ` [PATCH 21/21] time: " Gustavo Padovan
2012-06-14 9:22 ` [PATCH 00/21] BlueZ 5.0 patches Bastien Nocera
2012-06-14 12:03 ` Anderson Lizardo
2012-06-14 13:02 ` Szymon Janc
2012-06-14 12:18 ` Johan Hedberg
2012-06-14 13:34 ` Gustavo Padovan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).