* [PATCH] network: fix network Connect() method parameters
@ 2012-07-04 8:17 Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 02/28] remove the hciops plugin Gustavo Padovan
` (21 more replies)
0 siblings, 22 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
network/connection.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/network/connection.c b/network/connection.c
index 544ec3a..59423a9 100644
--- a/network/connection.c
+++ b/network/connection.c
@@ -554,7 +554,9 @@ static void path_unregister(void *data)
static const GDBusMethodTable connection_methods[] = {
{ GDBUS_ASYNC_METHOD("Connect",
- NULL, NULL, connection_connect) },
+ GDBUS_ARGS({"uuid", "s"}),
+ GDBUS_ARGS({"interface", "s"}),
+ connection_connect) },
{ GDBUS_METHOD("Disconnect",
NULL, NULL, connection_disconnect) },
{ GDBUS_METHOD("GetProperties",
--
1.7.10.2
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH -v2 02/28] remove the hciops plugin
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 03/28] headset: remove deprecated DBus methods Gustavo Padovan
` (20 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 7415979..5009ca8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -236,8 +236,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] 25+ messages in thread
* [PATCH -v2 03/28] headset: remove deprecated DBus methods
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 02/28] remove the hciops plugin Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 04/28] sink: remove deprecated DBus method Gustavo Padovan
` (19 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 ----------
test/test-telephony | 12 ----
3 files changed, 191 deletions(-)
diff --git a/audio/headset.c b/audio/headset.c
index b9c6265..1014c59 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 9b1737d..2419531 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 bd7d3b2..57ac7f0 100755
--- a/test/test-telephony
+++ b/test/test-telephony
@@ -44,7 +44,6 @@ if len(args) < 1:
subscriber <number>
speakergain <bdaddr> [level]
microphonegain <bdaddr> [level]
- play <bdaddr>
stop <bdaddr>
""" % sys.argv[0])
sys.exit(1)
@@ -99,17 +98,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] 25+ messages in thread
* [PATCH -v2 04/28] sink: remove deprecated DBus method
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 02/28] remove the hciops plugin Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 03/28] headset: remove deprecated DBus methods Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 12:31 ` [PATCH -v3 04/22] manager: remove deprecated ListAdapters() method Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 05/28] adapter: remove deprecated ListDevices() method Gustavo Padovan
` (18 subsequent siblings)
21 siblings, 1 reply; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 8ba4e2a..64e38f4 100644
--- a/audio/sink.c
+++ b/audio/sink.c
@@ -492,27 +492,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)
{
@@ -556,9 +535,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 2419531..ca430fc 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] 25+ messages in thread
* [PATCH -v2 05/28] adapter: remove deprecated ListDevices() method
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (2 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 04/28] sink: remove deprecated DBus method Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 12:31 ` [PATCH -v3 03/22] " Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 06/28] manager: remove deprecated ListAdapters() method Gustavo Padovan
` (17 subsequent siblings)
21 siblings, 1 reply; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 916e941..176843b 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 f922876..9315922 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] 25+ messages in thread
* [PATCH -v2 06/28] manager: remove deprecated ListAdapters() method
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (3 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 05/28] adapter: remove deprecated ListDevices() method Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 07/28] adapter: remove btd_adapter_encrypt_link() Gustavo Padovan
` (16 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 7061f64..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_DEPRECATED_METHOD("ListAdapters",
- NULL, GDBUS_ARGS({ "adapters", "ao" }),
- list_adapters) },
{ }
};
--
1.7.10.2
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH -v2 07/28] adapter: remove btd_adapter_encrypt_link()
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (4 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 06/28] manager: remove deprecated ListAdapters() method Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 08/28] adapter_ops: remove disable_cod_cache Gustavo Padovan
` (15 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 09a9a39..c08ba18 100644
--- a/input/device.c
+++ b/input/device.c
@@ -653,22 +653,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);
@@ -678,20 +674,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 9315922..b485c88 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] 25+ messages in thread
* [PATCH -v2 08/28] adapter_ops: remove disable_cod_cache
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (5 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 07/28] adapter: remove btd_adapter_encrypt_link() Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 09/28] manager: remove unused manager_add_adapter() Gustavo Padovan
` (14 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 b485c88..a043366 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] 25+ messages in thread
* [PATCH -v2 09/28] manager: remove unused manager_add_adapter()
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (6 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 08/28] adapter_ops: remove disable_cod_cache Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 10/28] adapter: make restore powered work again Gustavo Padovan
` (13 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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] 25+ messages in thread
* [PATCH -v2 10/28] adapter: make restore powered work again
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (7 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 09/28] manager: remove unused manager_add_adapter() Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 11/28] serial: remove SerialProxy interface Gustavo Padovan
` (12 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 a043366..1546aed 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] 25+ messages in thread
* [PATCH -v2 11/28] serial: remove SerialProxy interface
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (8 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 10/28] adapter: make restore powered work again Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 12/28] serial: remove unneeded headers include Gustavo Padovan
` (11 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 5009ca8..25d1026 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -190,7 +190,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] 25+ messages in thread
* [PATCH -v2 12/28] serial: remove unneeded headers include
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (9 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 11/28] serial: remove SerialProxy interface Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 13/28] input: remove unneeded header inclusions Gustavo Padovan
` (10 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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] 25+ messages in thread
* [PATCH -v2 13/28] input: remove unneeded header inclusions
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (10 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 12/28] serial: remove unneeded headers include Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 14/28] serial: remove old way to connect to a serial port Gustavo Padovan
` (9 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 c08ba18..f3ceabb 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] 25+ messages in thread
* [PATCH -v2 14/28] serial: remove old way to connect to a serial port
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (11 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 13/28] input: remove unneeded header inclusions Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 15/28] emulator: move it to the tools folder Gustavo Padovan
` (8 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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] 25+ messages in thread
* [PATCH -v2 15/28] emulator: move it to the tools folder
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (12 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 14/28] serial: remove old way to connect to a serial port Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 16/28] btmgmt: move to " Gustavo Padovan
` (7 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 c7d079e..aaf52c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,7 +88,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 1626a4b..e1be0fa 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] 25+ messages in thread
* [PATCH -v2 16/28] btmgmt: move to tools folder
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (13 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 15/28] emulator: move it to the tools folder Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 17/28] alert: move alert to profiles dir Gustavo Padovan
` (6 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 aaf52c3..63f6ae0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,7 +86,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 e1be0fa..e4cf238 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] 25+ messages in thread
* [PATCH -v2 17/28] alert: move alert to profiles dir
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (14 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 16/28] btmgmt: move to " Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 18/28] deviceinfo: move to profiles folder Gustavo Padovan
` (5 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 25d1026..e4874ac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -221,7 +221,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] 25+ messages in thread
* [PATCH -v2 18/28] deviceinfo: move to profiles folder
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (15 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 17/28] alert: move alert to profiles dir Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 20/28] thermometer: move to the " Gustavo Padovan
` (4 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
Makefile.am | 11 ++-
deviceinfo/deviceinfo.c | 195 --------------------------------------
deviceinfo/deviceinfo.h | 24 -----
deviceinfo/main.c | 52 ----------
deviceinfo/manager.c | 80 ----------------
deviceinfo/manager.h | 24 -----
profiles/deviceinfo/deviceinfo.c | 195 ++++++++++++++++++++++++++++++++++++++
profiles/deviceinfo/deviceinfo.h | 24 +++++
profiles/deviceinfo/main.c | 52 ++++++++++
profiles/deviceinfo/manager.c | 80 ++++++++++++++++
profiles/deviceinfo/manager.h | 24 +++++
11 files changed, 381 insertions(+), 380 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 e4874ac..d1bc65f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -216,8 +216,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 \
@@ -230,9 +229,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 4548553..0000000
--- a/deviceinfo/deviceinfo.c
+++ /dev/null
@@ -1,195 +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"
-
-#define PNP_ID_SIZE 7
-
-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[PNP_ID_SIZE];
- ssize_t vlen;
-
- if (status != 0) {
- error("Error reading PNP_ID value: %s", att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, len, value, sizeof(value));
- if (vlen < 0) {
- 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..4548553
--- /dev/null
+++ b/profiles/deviceinfo/deviceinfo.c
@@ -0,0 +1,195 @@
+/*
+ *
+ * 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"
+
+#define PNP_ID_SIZE 7
+
+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[PNP_ID_SIZE];
+ ssize_t vlen;
+
+ if (status != 0) {
+ error("Error reading PNP_ID value: %s", att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, len, value, sizeof(value));
+ if (vlen < 0) {
+ 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] 25+ messages in thread
* [PATCH -v2 20/28] thermometer: move to the profiles folder
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (16 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 18/28] deviceinfo: move to profiles folder Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 21/28] time: " Gustavo Padovan
` (3 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 | 1274 ++++++++++++++++++++++++++++++++++++
profiles/thermometer/thermometer.h | 25 +
thermometer/main.c | 70 --
thermometer/manager.c | 92 ---
thermometer/manager.h | 24 -
thermometer/thermometer.c | 1274 ------------------------------------
thermometer/thermometer.h | 25 -
11 files changed, 1490 insertions(+), 1488 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 6592c5c..b816e20 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -217,9 +217,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..087662e
--- /dev/null
+++ b/profiles/thermometer/thermometer.c
@@ -0,0 +1,1274 @@
+/*
+ *
+ * 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 */
+
+#define VALID_RANGE_DESC_SIZE 4
+#define TEMPERATURE_TYPE_SIZE 1
+#define MEASUREMENT_INTERVAL_SIZE 2
+
+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[VALID_RANGE_DESC_SIZE];
+ uint16_t max, min;
+ ssize_t vlen;
+
+ if (status != 0) {
+ DBG("Valid Range descriptor read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, len, value, sizeof(value));
+ if (vlen < 0) {
+ 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[TEMPERATURE_TYPE_SIZE];
+ ssize_t vlen;
+
+ if (status != 0) {
+ DBG("Temperature Type value read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, len, value, sizeof(value));
+ if (vlen < 0) {
+ 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[MEASUREMENT_INTERVAL_SIZE];
+ uint16_t interval;
+ ssize_t vlen;
+
+ if (status != 0) {
+ DBG("Measurement Interval value read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, len, value, sizeof(value));
+ if (vlen < 0) {
+ 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;
+ uint16_t handle, olen;
+ GSList *l;
+ int plen;
+
+ 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);
+
+ opdu = g_attrib_get_buffer(t->attrib, &plen);
+ olen = enc_confirmation(opdu, plen);
+
+ 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 087662e..0000000
--- a/thermometer/thermometer.c
+++ /dev/null
@@ -1,1274 +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 */
-
-#define VALID_RANGE_DESC_SIZE 4
-#define TEMPERATURE_TYPE_SIZE 1
-#define MEASUREMENT_INTERVAL_SIZE 2
-
-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[VALID_RANGE_DESC_SIZE];
- uint16_t max, min;
- ssize_t vlen;
-
- if (status != 0) {
- DBG("Valid Range descriptor read failed: %s",
- att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, len, value, sizeof(value));
- if (vlen < 0) {
- 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[TEMPERATURE_TYPE_SIZE];
- ssize_t vlen;
-
- if (status != 0) {
- DBG("Temperature Type value read failed: %s",
- att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, len, value, sizeof(value));
- if (vlen < 0) {
- 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[MEASUREMENT_INTERVAL_SIZE];
- uint16_t interval;
- ssize_t vlen;
-
- if (status != 0) {
- DBG("Measurement Interval value read failed: %s",
- att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, len, value, sizeof(value));
- if (vlen < 0) {
- 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;
- uint16_t handle, olen;
- GSList *l;
- int plen;
-
- 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);
-
- opdu = g_attrib_get_buffer(t->attrib, &plen);
- olen = enc_confirmation(opdu, plen);
-
- 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] 25+ messages in thread
* [PATCH -v2 21/28] time: move to the profiles folder
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (17 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 20/28] thermometer: move to the " Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 23/28] test: add test-audiosource Gustavo Padovan
` (2 subsequent siblings)
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 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 b816e20..3a5f616 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -224,7 +224,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] 25+ messages in thread
* [PATCH -v2 23/28] test: add test-audiosource
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (18 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 21/28] time: " Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 25/28] serial: move it to the profiles folder Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 27/28] cups: move it to " Gustavo Padovan
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
Makefile.tools | 2 +-
test/test-audiosource | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 1 deletion(-)
create mode 100644 test/test-audiosource
diff --git a/Makefile.tools b/Makefile.tools
index e4cf238..3cfc6f3 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -222,4 +222,4 @@ EXTRA_DIST += test/sap-client test/hsplay test/hsmicro \
test/test-serial-proxy test/test-health test/test-health-sink \
test/service-record.dtd test/service-did.xml \
test/service-spp.xml test/service-opp.xml test/service-ftp.xml \
- test/simple-player test/test-nap
+ test/simple-player test/test-nap test/test-audiosource
diff --git a/test/test-audiosource b/test/test-audiosource
new file mode 100644
index 0000000..c89ff7c
--- /dev/null
+++ b/test/test-audiosource
@@ -0,0 +1,46 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+from optparse import OptionParser, make_option
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
+
+option_list = [
+ make_option("-i", "--device", action="store",
+ type="string", dest="dev_id"),
+ ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+ adapter_path = manager.FindAdapter(options.dev_id)
+else:
+ adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+ "org.bluez.Adapter")
+
+if len(args) < 2:
+ print """Usage: %s <command>
+
+ connect <bdaddr>
+ disconnect <bdaddr>
+ """ % sys.argv[0]
+ sys.exit(1)
+
+device = adapter.FindDevice(args[1])
+audio = dbus.Interface(bus.get_object("org.bluez", device),
+ "org.bluez.AudioSource")
+
+if args[0] == "connect":
+ audio.Connect()
+elif args[0] == "disconnect":
+ audio.Disconnect()
+else:
+ print "Unknown command"
+ sys.exit(1)
+
--
1.7.10.2
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH -v2 25/28] serial: move it to the profiles folder
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (19 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 23/28] test: add test-audiosource Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 27/28] cups: move it to " Gustavo Padovan
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
Makefile.am | 8 +-
profiles/serial/main.c | 59 ++++++
profiles/serial/manager.c | 127 ++++++++++++
profiles/serial/manager.h | 25 +++
profiles/serial/port.c | 452 +++++++++++++++++++++++++++++++++++++++++++
profiles/serial/port.h | 29 +++
profiles/serial/serial.conf | 10 +
serial/main.c | 59 ------
serial/manager.c | 127 ------------
serial/manager.h | 25 ---
serial/port.c | 452 -------------------------------------------
serial/port.h | 29 ---
serial/serial.conf | 10 -
13 files changed, 706 insertions(+), 706 deletions(-)
create mode 100644 profiles/serial/main.c
create mode 100644 profiles/serial/manager.c
create mode 100644 profiles/serial/manager.h
create mode 100644 profiles/serial/port.c
create mode 100644 profiles/serial/port.h
create mode 100644 profiles/serial/serial.conf
delete mode 100644 serial/main.c
delete mode 100644 serial/manager.c
delete mode 100644 serial/manager.h
delete mode 100644 serial/port.c
delete mode 100644 serial/port.h
delete mode 100644 serial/serial.conf
diff --git a/Makefile.am b/Makefile.am
index a0d99f8..3807a42 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -188,9 +188,9 @@ endif
if SERIALPLUGIN
builtin_modules += serial
-builtin_sources += serial/main.c \
- serial/manager.h serial/manager.c \
- serial/port.h serial/port.c
+builtin_sources += profiles/serial/main.c \
+ profiles/serial/manager.h profiles/serial/manager.c \
+ profiles/serial/port.h profiles/serial/port.c
endif
if NETWORKPLUGIN
@@ -337,7 +337,7 @@ endif
EXTRA_DIST += src/genbuiltin src/bluetooth.conf src/org.bluez.service \
src/main.conf network/network.conf \
- profiles/input/input.conf serial/serial.conf \
+ profiles/input/input.conf profiles/serial/serial.conf \
audio/audio.conf audio/telephony-dummy.c \
audio/telephony-maemo5.c audio/telephony-ofono.c \
audio/telephony-maemo6.c sap/sap-dummy.c sap/sap-u8500.c \
diff --git a/profiles/serial/main.c b/profiles/serial/main.c
new file mode 100644
index 0000000..38ded03
--- /dev/null
+++ b/profiles/serial/main.c
@@ -0,0 +1,59 @@
+/*
+ *
+ * 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 <errno.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection;
+
+static int serial_init(void)
+{
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (connection == NULL)
+ return -EIO;
+
+ if (serial_manager_init(connection) < 0) {
+ dbus_connection_unref(connection);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void serial_exit(void)
+{
+ serial_manager_exit();
+
+ dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(serial, VERSION,
+ BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, serial_init, serial_exit)
diff --git a/profiles/serial/manager.c b/profiles/serial/manager.c
new file mode 100644
index 0000000..6f3fc1f
--- /dev/null
+++ b/profiles/serial/manager.c
@@ -0,0 +1,127 @@
+/*
+ *
+ * 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 <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
+
+#include <gdbus.h>
+
+#include "adapter.h"
+#include "device.h"
+
+#include "log.h"
+
+#include "port.h"
+#include "manager.h"
+
+static DBusConnection *connection = NULL;
+
+static int serial_probe(struct btd_device *device, const char *uuid)
+{
+ struct btd_adapter *adapter = device_get_adapter(device);
+ const gchar *path = device_get_path(device);
+ sdp_list_t *protos;
+ int ch;
+ bdaddr_t src, dst;
+ const sdp_record_t *rec;
+
+ DBG("path %s: %s", path, uuid);
+
+ rec = btd_device_get_record(device, uuid);
+ if (!rec)
+ return -EINVAL;
+
+ if (sdp_get_access_protos(rec, &protos) < 0)
+ return -EINVAL;
+
+ ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+
+ if (ch < 1 || ch > 30) {
+ error("Channel out of range: %d", ch);
+ return -EINVAL;
+ }
+
+ adapter_get_address(adapter, &src);
+ device_get_address(device, &dst, NULL);
+
+ return port_register(connection, path, &src, &dst, uuid, ch);
+}
+
+static void serial_remove(struct btd_device *device)
+{
+ const gchar *path = device_get_path(device);
+
+ DBG("path %s", path);
+
+ port_unregister(path);
+}
+
+
+static int port_probe(struct btd_device *device, GSList *uuids)
+{
+ while (uuids) {
+ serial_probe(device, uuids->data);
+ uuids = uuids->next;
+ }
+
+ return 0;
+}
+
+static void port_remove(struct btd_device *device)
+{
+ return serial_remove(device);
+}
+
+static struct btd_device_driver serial_port_driver = {
+ .name = "serial-port",
+ .uuids = BTD_UUIDS(RFCOMM_UUID_STR),
+ .probe = port_probe,
+ .remove = port_remove,
+};
+
+int serial_manager_init(DBusConnection *conn)
+{
+ connection = dbus_connection_ref(conn);
+
+ btd_register_device_driver(&serial_port_driver);
+
+ return 0;
+}
+
+void serial_manager_exit(void)
+{
+ btd_unregister_device_driver(&serial_port_driver);
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
diff --git a/profiles/serial/manager.h b/profiles/serial/manager.h
new file mode 100644
index 0000000..c8b96e8
--- /dev/null
+++ b/profiles/serial/manager.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * 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 serial_manager_init(DBusConnection *conn);
+void serial_manager_exit(void);
diff --git a/profiles/serial/port.c b/profiles/serial/port.c
new file mode 100644
index 0000000..f2b7184
--- /dev/null
+++ b/profiles/serial/port.c
@@ -0,0 +1,452 @@
+/*
+ *
+ * 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 <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "log.h"
+#include "glib-helper.h"
+#include "sdp-client.h"
+#include "btio.h"
+
+#include "error.h"
+#include "manager.h"
+#include "adapter.h"
+#include "device.h"
+#include "storage.h"
+#include "port.h"
+
+#define SERIAL_PORT_INTERFACE "org.bluez.Serial"
+
+#define MAX_OPEN_TRIES 5
+#define OPEN_WAIT 300 /* ms. udev node creation retry wait */
+
+struct serial_device {
+ DBusConnection *conn; /* for name listener handling */
+ bdaddr_t src; /* Source (local) address */
+ bdaddr_t dst; /* Destination address */
+ char *path; /* Device path */
+ GSList *ports; /* Available ports */
+};
+
+struct serial_port {
+ DBusMessage *msg; /* for name listener handling */
+ int16_t id; /* RFCOMM device id */
+ uint8_t channel; /* RFCOMM channel */
+ char *uuid; /* service identification */
+ GIOChannel *io; /* BtIO channel */
+ guint listener_id;
+ struct serial_device *device;
+};
+
+static GSList *devices = NULL;
+
+static struct serial_device *find_device(GSList *devices, const char *path)
+{
+ GSList *l;
+
+ for (l = devices; l != NULL; l = l->next) {
+ struct serial_device *device = l->data;
+
+ if (!strcmp(device->path, path))
+ return device;
+ }
+
+ return NULL;
+}
+
+static struct serial_port *find_port(GSList *ports, const char *pattern)
+{
+ GSList *l;
+ int channel;
+ char *endptr = NULL;
+
+ channel = strtol(pattern, &endptr, 10);
+
+ for (l = ports; l != NULL; l = l->next) {
+ struct serial_port *port = l->data;
+ char *uuid_str;
+ int ret;
+
+ if (port->uuid && !strcasecmp(port->uuid, pattern))
+ return port;
+
+ if (endptr && *endptr == '\0' && port->channel == channel)
+ return port;
+
+ if (!port->uuid)
+ continue;
+
+ uuid_str = bt_name2string(pattern);
+ if (!uuid_str)
+ continue;
+
+ ret = strcasecmp(port->uuid, uuid_str);
+ g_free(uuid_str);
+ if (ret == 0)
+ return port;
+ }
+
+ return NULL;
+}
+
+static void port_release(struct serial_port *port)
+{
+ if (port->id < 0) {
+ if (port->io) {
+ g_io_channel_shutdown(port->io, TRUE, NULL);
+ g_io_channel_unref(port->io);
+ port->io = NULL;
+ } else
+ bt_cancel_discovery(&port->device->src,
+ &port->device->dst);
+
+ }
+}
+
+static void serial_port_free(void *data)
+{
+ struct serial_port *port = data;
+ struct serial_device *device = port->device;
+
+ if (device && port->listener_id > 0)
+ g_dbus_remove_watch(device->conn, port->listener_id);
+
+ port_release(port);
+
+ g_free(port->uuid);
+ g_free(port);
+}
+
+static void serial_device_free(void *data)
+{
+ struct serial_device *device = data;
+
+ g_free(device->path);
+ if (device->conn)
+ dbus_connection_unref(device->conn);
+ g_free(device);
+}
+
+static void port_owner_exited(DBusConnection *conn, void *user_data)
+{
+ struct serial_port *port = user_data;
+
+ port_release(port);
+
+ port->listener_id = 0;
+}
+
+static void path_unregister(void *data)
+{
+ struct serial_device *device = data;
+
+ DBG("Unregistered interface %s on path %s", SERIAL_PORT_INTERFACE,
+ device->path);
+
+ devices = g_slist_remove(devices, device);
+ serial_device_free(device);
+}
+
+void port_release_all(void)
+{
+ g_slist_free_full(devices, serial_device_free);
+}
+
+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;
+ int sk;
+ DBusMessage *reply;
+
+ /* Owner exited? */
+ if (!port->listener_id)
+ return;
+
+ if (conn_err) {
+ error("%s", conn_err->message);
+ reply = btd_error_failed(port->msg, conn_err->message);
+ g_dbus_send_message(device->conn, reply);
+ goto fail;
+ }
+
+ 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);
+
+ close(sk);
+
+fail:
+ g_dbus_remove_watch(device->conn, port->listener_id);
+ port->listener_id = 0;
+}
+
+static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+ struct serial_port *port = user_data;
+ struct serial_device *device = port->device;
+ sdp_record_t *record = NULL;
+ sdp_list_t *protos;
+ DBusMessage *reply;
+ GError *gerr = NULL;
+
+ if (!port->listener_id)
+ return;
+
+ if (err < 0) {
+ error("Unable to get service record: %s (%d)", strerror(-err),
+ -err);
+ reply = btd_error_failed(port->msg, strerror(-err));
+ goto failed;
+ }
+
+ if (!recs || !recs->data) {
+ error("No record found");
+ reply = btd_error_failed(port->msg, "No record found");
+ goto failed;
+ }
+
+ record = recs->data;
+
+ if (sdp_get_access_protos(record, &protos) < 0) {
+ error("Unable to get access protos from port record");
+ reply = btd_error_failed(port->msg, "Invalid channel");
+ goto failed;
+ }
+
+ port->channel = sdp_get_proto_port(protos, RFCOMM_UUID);
+
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+
+ port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port,
+ NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &device->src,
+ BT_IO_OPT_DEST_BDADDR, &device->dst,
+ BT_IO_OPT_CHANNEL, port->channel,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_INVALID);
+ if (!port->io) {
+ error("%s", gerr->message);
+ reply = btd_error_failed(port->msg, gerr->message);
+ g_error_free(gerr);
+ goto failed;
+ }
+
+ return;
+
+failed:
+ g_dbus_remove_watch(device->conn, port->listener_id);
+ port->listener_id = 0;
+ g_dbus_send_message(device->conn, reply);
+}
+
+static int connect_port(struct serial_port *port)
+{
+ struct serial_device *device = port->device;
+ uuid_t uuid;
+ int err;
+
+ if (!port->uuid)
+ goto connect;
+
+ err = bt_string2uuid(&uuid, port->uuid);
+ if (err < 0)
+ return err;
+
+ sdp_uuid128_to_uuid(&uuid);
+
+ return bt_search_service(&device->src, &device->dst, &uuid,
+ get_record_cb, port, NULL);
+
+connect:
+ port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port,
+ NULL, NULL,
+ BT_IO_OPT_SOURCE_BDADDR, &device->src,
+ BT_IO_OPT_DEST_BDADDR, &device->dst,
+ BT_IO_OPT_CHANNEL, port->channel,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_INVALID);
+ if (port->io == NULL)
+ return -EIO;
+
+ return 0;
+}
+
+static struct serial_port *create_port(struct serial_device *device,
+ const char *uuid, uint8_t channel)
+{
+ struct serial_port *port;
+
+ port = g_new0(struct serial_port, 1);
+ port->uuid = g_strdup(uuid);
+ port->channel = channel;
+ port->device = device;
+ port->id = -1;
+
+ device->ports = g_slist_append(device->ports, port);
+
+ return port;
+}
+
+static DBusMessage *port_connect(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct serial_device *device = user_data;
+ struct serial_port *port;
+ const char *pattern;
+ int err;
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID) == FALSE)
+ return NULL;
+
+ port = find_port(device->ports, pattern);
+ if (!port) {
+ char *endptr = NULL;
+ int channel;
+
+ channel = strtol(pattern, &endptr, 10);
+ if ((endptr && *endptr != '\0') || channel < 1 || channel > 30)
+ return btd_error_does_not_exist(msg);
+
+ port = create_port(device, NULL, channel);
+ }
+
+ if (port->listener_id)
+ return btd_error_failed(msg, "Port already in use");
+
+ port->listener_id = g_dbus_add_disconnect_watch(conn,
+ dbus_message_get_sender(msg),
+ port_owner_exited, port,
+ NULL);
+
+ port->msg = dbus_message_ref(msg);
+
+ err = connect_port(port);
+ if (err < 0) {
+ error("%s", strerror(-err));
+ g_dbus_remove_watch(conn, port->listener_id);
+ port->listener_id = 0;
+
+ return btd_error_failed(msg, strerror(-err));
+ }
+
+ return NULL;
+}
+
+static const GDBusMethodTable port_methods[] = {
+ { GDBUS_ASYNC_METHOD("Connect",
+ GDBUS_ARGS({ "pattern", "s" }), GDBUS_ARGS({ "fd", "s" }),
+ port_connect) },
+ { }
+};
+
+static struct serial_device *create_serial_device(DBusConnection *conn,
+ const char *path, bdaddr_t *src,
+ bdaddr_t *dst)
+{
+ struct serial_device *device;
+
+ device = g_new0(struct serial_device, 1);
+ device->conn = dbus_connection_ref(conn);
+ bacpy(&device->dst, dst);
+ bacpy(&device->src, src);
+ device->path = g_strdup(path);
+
+ if (!g_dbus_register_interface(conn, path,
+ SERIAL_PORT_INTERFACE,
+ port_methods, NULL, NULL,
+ device, path_unregister)) {
+ error("D-Bus failed to register %s interface",
+ SERIAL_PORT_INTERFACE);
+ serial_device_free(device);
+ return NULL;
+ }
+
+ DBG("Registered interface %s on path %s",
+ SERIAL_PORT_INTERFACE, path);
+
+ return device;
+}
+
+int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
+ bdaddr_t *dst, const char *uuid, uint8_t channel)
+{
+ struct serial_device *device;
+ struct serial_port *port;
+
+ device = find_device(devices, path);
+ if (!device) {
+ device = create_serial_device(conn, path, src, dst);
+ if (!device)
+ return -1;
+ devices = g_slist_append(devices, device);
+ }
+
+ if (find_port(device->ports, uuid))
+ return 0;
+
+ port = g_new0(struct serial_port, 1);
+ port->uuid = g_strdup(uuid);
+ port->channel = channel;
+ port->device = device;
+ port->id = -1;
+
+ device->ports = g_slist_append(device->ports, port);
+
+ return 0;
+}
+
+int port_unregister(const char *path)
+{
+ struct serial_device *device;
+
+ device = find_device(devices, path);
+ if (!device)
+ return -ENOENT;
+
+ g_slist_free_full(device->ports, serial_port_free);
+
+ g_dbus_unregister_interface(device->conn, path, SERIAL_PORT_INTERFACE);
+
+ return 0;
+}
diff --git a/profiles/serial/port.h b/profiles/serial/port.h
new file mode 100644
index 0000000..74ac9f0
--- /dev/null
+++ b/profiles/serial/port.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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
+ *
+ */
+
+void port_release_all(void);
+
+int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
+ bdaddr_t *dst, const char *name, uint8_t channel);
+
+int port_unregister(const char *path);
diff --git a/profiles/serial/serial.conf b/profiles/serial/serial.conf
new file mode 100644
index 0000000..43ee6af
--- /dev/null
+++ b/profiles/serial/serial.conf
@@ -0,0 +1,10 @@
+# Configuration file for serial
+
+# There could be multiple proxy sections, the format is [Proxy <user chosen name>]
+#[Proxy DUN]
+
+# UUID for DUN proxy service
+#UUID=00001103-0000-1000-8000-00805F9B34FB
+
+# Address for device node
+#Address=/dev/ttyx
diff --git a/serial/main.c b/serial/main.c
deleted file mode 100644
index 38ded03..0000000
--- a/serial/main.c
+++ /dev/null
@@ -1,59 +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 <errno.h>
-
-#include <gdbus.h>
-
-#include "plugin.h"
-#include "manager.h"
-
-static DBusConnection *connection;
-
-static int serial_init(void)
-{
- connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
- if (connection == NULL)
- return -EIO;
-
- if (serial_manager_init(connection) < 0) {
- dbus_connection_unref(connection);
- return -EIO;
- }
-
- return 0;
-}
-
-static void serial_exit(void)
-{
- serial_manager_exit();
-
- dbus_connection_unref(connection);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(serial, VERSION,
- BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, serial_init, serial_exit)
diff --git a/serial/manager.c b/serial/manager.c
deleted file mode 100644
index 6f3fc1f..0000000
--- a/serial/manager.c
+++ /dev/null
@@ -1,127 +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 <errno.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/uuid.h>
-
-#include <gdbus.h>
-
-#include "adapter.h"
-#include "device.h"
-
-#include "log.h"
-
-#include "port.h"
-#include "manager.h"
-
-static DBusConnection *connection = NULL;
-
-static int serial_probe(struct btd_device *device, const char *uuid)
-{
- struct btd_adapter *adapter = device_get_adapter(device);
- const gchar *path = device_get_path(device);
- sdp_list_t *protos;
- int ch;
- bdaddr_t src, dst;
- const sdp_record_t *rec;
-
- DBG("path %s: %s", path, uuid);
-
- rec = btd_device_get_record(device, uuid);
- if (!rec)
- return -EINVAL;
-
- if (sdp_get_access_protos(rec, &protos) < 0)
- return -EINVAL;
-
- ch = sdp_get_proto_port(protos, RFCOMM_UUID);
- sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
- sdp_list_free(protos, NULL);
-
- if (ch < 1 || ch > 30) {
- error("Channel out of range: %d", ch);
- return -EINVAL;
- }
-
- adapter_get_address(adapter, &src);
- device_get_address(device, &dst, NULL);
-
- return port_register(connection, path, &src, &dst, uuid, ch);
-}
-
-static void serial_remove(struct btd_device *device)
-{
- const gchar *path = device_get_path(device);
-
- DBG("path %s", path);
-
- port_unregister(path);
-}
-
-
-static int port_probe(struct btd_device *device, GSList *uuids)
-{
- while (uuids) {
- serial_probe(device, uuids->data);
- uuids = uuids->next;
- }
-
- return 0;
-}
-
-static void port_remove(struct btd_device *device)
-{
- return serial_remove(device);
-}
-
-static struct btd_device_driver serial_port_driver = {
- .name = "serial-port",
- .uuids = BTD_UUIDS(RFCOMM_UUID_STR),
- .probe = port_probe,
- .remove = port_remove,
-};
-
-int serial_manager_init(DBusConnection *conn)
-{
- connection = dbus_connection_ref(conn);
-
- btd_register_device_driver(&serial_port_driver);
-
- return 0;
-}
-
-void serial_manager_exit(void)
-{
- btd_unregister_device_driver(&serial_port_driver);
-
- dbus_connection_unref(connection);
- connection = NULL;
-}
diff --git a/serial/manager.h b/serial/manager.h
deleted file mode 100644
index c8b96e8..0000000
--- a/serial/manager.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 serial_manager_init(DBusConnection *conn);
-void serial_manager_exit(void);
diff --git a/serial/port.c b/serial/port.c
deleted file mode 100644
index f2b7184..0000000
--- a/serial/port.c
+++ /dev/null
@@ -1,452 +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 <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "glib-helper.h"
-#include "sdp-client.h"
-#include "btio.h"
-
-#include "error.h"
-#include "manager.h"
-#include "adapter.h"
-#include "device.h"
-#include "storage.h"
-#include "port.h"
-
-#define SERIAL_PORT_INTERFACE "org.bluez.Serial"
-
-#define MAX_OPEN_TRIES 5
-#define OPEN_WAIT 300 /* ms. udev node creation retry wait */
-
-struct serial_device {
- DBusConnection *conn; /* for name listener handling */
- bdaddr_t src; /* Source (local) address */
- bdaddr_t dst; /* Destination address */
- char *path; /* Device path */
- GSList *ports; /* Available ports */
-};
-
-struct serial_port {
- DBusMessage *msg; /* for name listener handling */
- int16_t id; /* RFCOMM device id */
- uint8_t channel; /* RFCOMM channel */
- char *uuid; /* service identification */
- GIOChannel *io; /* BtIO channel */
- guint listener_id;
- struct serial_device *device;
-};
-
-static GSList *devices = NULL;
-
-static struct serial_device *find_device(GSList *devices, const char *path)
-{
- GSList *l;
-
- for (l = devices; l != NULL; l = l->next) {
- struct serial_device *device = l->data;
-
- if (!strcmp(device->path, path))
- return device;
- }
-
- return NULL;
-}
-
-static struct serial_port *find_port(GSList *ports, const char *pattern)
-{
- GSList *l;
- int channel;
- char *endptr = NULL;
-
- channel = strtol(pattern, &endptr, 10);
-
- for (l = ports; l != NULL; l = l->next) {
- struct serial_port *port = l->data;
- char *uuid_str;
- int ret;
-
- if (port->uuid && !strcasecmp(port->uuid, pattern))
- return port;
-
- if (endptr && *endptr == '\0' && port->channel == channel)
- return port;
-
- if (!port->uuid)
- continue;
-
- uuid_str = bt_name2string(pattern);
- if (!uuid_str)
- continue;
-
- ret = strcasecmp(port->uuid, uuid_str);
- g_free(uuid_str);
- if (ret == 0)
- return port;
- }
-
- return NULL;
-}
-
-static void port_release(struct serial_port *port)
-{
- if (port->id < 0) {
- if (port->io) {
- g_io_channel_shutdown(port->io, TRUE, NULL);
- g_io_channel_unref(port->io);
- port->io = NULL;
- } else
- bt_cancel_discovery(&port->device->src,
- &port->device->dst);
-
- }
-}
-
-static void serial_port_free(void *data)
-{
- struct serial_port *port = data;
- struct serial_device *device = port->device;
-
- if (device && port->listener_id > 0)
- g_dbus_remove_watch(device->conn, port->listener_id);
-
- port_release(port);
-
- g_free(port->uuid);
- g_free(port);
-}
-
-static void serial_device_free(void *data)
-{
- struct serial_device *device = data;
-
- g_free(device->path);
- if (device->conn)
- dbus_connection_unref(device->conn);
- g_free(device);
-}
-
-static void port_owner_exited(DBusConnection *conn, void *user_data)
-{
- struct serial_port *port = user_data;
-
- port_release(port);
-
- port->listener_id = 0;
-}
-
-static void path_unregister(void *data)
-{
- struct serial_device *device = data;
-
- DBG("Unregistered interface %s on path %s", SERIAL_PORT_INTERFACE,
- device->path);
-
- devices = g_slist_remove(devices, device);
- serial_device_free(device);
-}
-
-void port_release_all(void)
-{
- g_slist_free_full(devices, serial_device_free);
-}
-
-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;
- int sk;
- DBusMessage *reply;
-
- /* Owner exited? */
- if (!port->listener_id)
- return;
-
- if (conn_err) {
- error("%s", conn_err->message);
- reply = btd_error_failed(port->msg, conn_err->message);
- g_dbus_send_message(device->conn, reply);
- goto fail;
- }
-
- 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);
-
- close(sk);
-
-fail:
- g_dbus_remove_watch(device->conn, port->listener_id);
- port->listener_id = 0;
-}
-
-static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
-{
- struct serial_port *port = user_data;
- struct serial_device *device = port->device;
- sdp_record_t *record = NULL;
- sdp_list_t *protos;
- DBusMessage *reply;
- GError *gerr = NULL;
-
- if (!port->listener_id)
- return;
-
- if (err < 0) {
- error("Unable to get service record: %s (%d)", strerror(-err),
- -err);
- reply = btd_error_failed(port->msg, strerror(-err));
- goto failed;
- }
-
- if (!recs || !recs->data) {
- error("No record found");
- reply = btd_error_failed(port->msg, "No record found");
- goto failed;
- }
-
- record = recs->data;
-
- if (sdp_get_access_protos(record, &protos) < 0) {
- error("Unable to get access protos from port record");
- reply = btd_error_failed(port->msg, "Invalid channel");
- goto failed;
- }
-
- port->channel = sdp_get_proto_port(protos, RFCOMM_UUID);
-
- sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
- sdp_list_free(protos, NULL);
-
- port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port,
- NULL, &gerr,
- BT_IO_OPT_SOURCE_BDADDR, &device->src,
- BT_IO_OPT_DEST_BDADDR, &device->dst,
- BT_IO_OPT_CHANNEL, port->channel,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
- BT_IO_OPT_INVALID);
- if (!port->io) {
- error("%s", gerr->message);
- reply = btd_error_failed(port->msg, gerr->message);
- g_error_free(gerr);
- goto failed;
- }
-
- return;
-
-failed:
- g_dbus_remove_watch(device->conn, port->listener_id);
- port->listener_id = 0;
- g_dbus_send_message(device->conn, reply);
-}
-
-static int connect_port(struct serial_port *port)
-{
- struct serial_device *device = port->device;
- uuid_t uuid;
- int err;
-
- if (!port->uuid)
- goto connect;
-
- err = bt_string2uuid(&uuid, port->uuid);
- if (err < 0)
- return err;
-
- sdp_uuid128_to_uuid(&uuid);
-
- return bt_search_service(&device->src, &device->dst, &uuid,
- get_record_cb, port, NULL);
-
-connect:
- port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port,
- NULL, NULL,
- BT_IO_OPT_SOURCE_BDADDR, &device->src,
- BT_IO_OPT_DEST_BDADDR, &device->dst,
- BT_IO_OPT_CHANNEL, port->channel,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
- BT_IO_OPT_INVALID);
- if (port->io == NULL)
- return -EIO;
-
- return 0;
-}
-
-static struct serial_port *create_port(struct serial_device *device,
- const char *uuid, uint8_t channel)
-{
- struct serial_port *port;
-
- port = g_new0(struct serial_port, 1);
- port->uuid = g_strdup(uuid);
- port->channel = channel;
- port->device = device;
- port->id = -1;
-
- device->ports = g_slist_append(device->ports, port);
-
- return port;
-}
-
-static DBusMessage *port_connect(DBusConnection *conn,
- DBusMessage *msg, void *user_data)
-{
- struct serial_device *device = user_data;
- struct serial_port *port;
- const char *pattern;
- int err;
-
- if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
- DBUS_TYPE_INVALID) == FALSE)
- return NULL;
-
- port = find_port(device->ports, pattern);
- if (!port) {
- char *endptr = NULL;
- int channel;
-
- channel = strtol(pattern, &endptr, 10);
- if ((endptr && *endptr != '\0') || channel < 1 || channel > 30)
- return btd_error_does_not_exist(msg);
-
- port = create_port(device, NULL, channel);
- }
-
- if (port->listener_id)
- return btd_error_failed(msg, "Port already in use");
-
- port->listener_id = g_dbus_add_disconnect_watch(conn,
- dbus_message_get_sender(msg),
- port_owner_exited, port,
- NULL);
-
- port->msg = dbus_message_ref(msg);
-
- err = connect_port(port);
- if (err < 0) {
- error("%s", strerror(-err));
- g_dbus_remove_watch(conn, port->listener_id);
- port->listener_id = 0;
-
- return btd_error_failed(msg, strerror(-err));
- }
-
- return NULL;
-}
-
-static const GDBusMethodTable port_methods[] = {
- { GDBUS_ASYNC_METHOD("Connect",
- GDBUS_ARGS({ "pattern", "s" }), GDBUS_ARGS({ "fd", "s" }),
- port_connect) },
- { }
-};
-
-static struct serial_device *create_serial_device(DBusConnection *conn,
- const char *path, bdaddr_t *src,
- bdaddr_t *dst)
-{
- struct serial_device *device;
-
- device = g_new0(struct serial_device, 1);
- device->conn = dbus_connection_ref(conn);
- bacpy(&device->dst, dst);
- bacpy(&device->src, src);
- device->path = g_strdup(path);
-
- if (!g_dbus_register_interface(conn, path,
- SERIAL_PORT_INTERFACE,
- port_methods, NULL, NULL,
- device, path_unregister)) {
- error("D-Bus failed to register %s interface",
- SERIAL_PORT_INTERFACE);
- serial_device_free(device);
- return NULL;
- }
-
- DBG("Registered interface %s on path %s",
- SERIAL_PORT_INTERFACE, path);
-
- return device;
-}
-
-int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
- bdaddr_t *dst, const char *uuid, uint8_t channel)
-{
- struct serial_device *device;
- struct serial_port *port;
-
- device = find_device(devices, path);
- if (!device) {
- device = create_serial_device(conn, path, src, dst);
- if (!device)
- return -1;
- devices = g_slist_append(devices, device);
- }
-
- if (find_port(device->ports, uuid))
- return 0;
-
- port = g_new0(struct serial_port, 1);
- port->uuid = g_strdup(uuid);
- port->channel = channel;
- port->device = device;
- port->id = -1;
-
- device->ports = g_slist_append(device->ports, port);
-
- return 0;
-}
-
-int port_unregister(const char *path)
-{
- struct serial_device *device;
-
- device = find_device(devices, path);
- if (!device)
- return -ENOENT;
-
- g_slist_free_full(device->ports, serial_port_free);
-
- g_dbus_unregister_interface(device->conn, path, SERIAL_PORT_INTERFACE);
-
- return 0;
-}
diff --git a/serial/port.h b/serial/port.h
deleted file mode 100644
index 74ac9f0..0000000
--- a/serial/port.h
+++ /dev/null
@@ -1,29 +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
- *
- */
-
-void port_release_all(void);
-
-int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
- bdaddr_t *dst, const char *name, uint8_t channel);
-
-int port_unregister(const char *path);
diff --git a/serial/serial.conf b/serial/serial.conf
deleted file mode 100644
index 43ee6af..0000000
--- a/serial/serial.conf
+++ /dev/null
@@ -1,10 +0,0 @@
-# Configuration file for serial
-
-# There could be multiple proxy sections, the format is [Proxy <user chosen name>]
-#[Proxy DUN]
-
-# UUID for DUN proxy service
-#UUID=00001103-0000-1000-8000-00805F9B34FB
-
-# Address for device node
-#Address=/dev/ttyx
--
1.7.10.2
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH -v2 27/28] cups: move it to profiles folder
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
` (20 preceding siblings ...)
2012-07-04 8:17 ` [PATCH -v2 25/28] serial: move it to the profiles folder Gustavo Padovan
@ 2012-07-04 8:17 ` Gustavo Padovan
21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 8:17 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
Makefile.tools | 12 +-
cups/cups.h | 38 ---
cups/hcrp.c | 368 ---------------------
cups/main.c | 896 --------------------------------------------------
cups/sdp.c | 119 -------
cups/spp.c | 118 -------
profiles/cups/cups.h | 38 +++
profiles/cups/hcrp.c | 368 +++++++++++++++++++++
profiles/cups/main.c | 896 ++++++++++++++++++++++++++++++++++++++++++++++++++
profiles/cups/sdp.c | 119 +++++++
profiles/cups/spp.c | 118 +++++++
11 files changed, 1547 insertions(+), 1543 deletions(-)
delete mode 100644 cups/cups.h
delete mode 100644 cups/hcrp.c
delete mode 100644 cups/main.c
delete mode 100644 cups/sdp.c
delete mode 100644 cups/spp.c
create mode 100644 profiles/cups/cups.h
create mode 100644 profiles/cups/hcrp.c
create mode 100644 profiles/cups/main.c
create mode 100644 profiles/cups/sdp.c
create mode 100644 profiles/cups/spp.c
diff --git a/Makefile.tools b/Makefile.tools
index 3cfc6f3..35e2644 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -148,12 +148,16 @@ EXTRA_DIST += tools/dfubabel.1 tools/avctrl.8
if CUPS
cupsdir = $(libdir)/cups/backend
-cups_PROGRAMS = cups/bluetooth
+cups_PROGRAMS = profiles/cups/bluetooth
-cups_bluetooth_SOURCES = $(gdbus_sources) cups/main.c cups/cups.h \
- cups/sdp.c cups/spp.c cups/hcrp.c
+profiles_cups_bluetooth_SOURCES = $(gdbus_sources) profiles/cups/main.c \
+ profiles/cups/cups.h \
+ profiles/cups/sdp.c \
+ profiles/cups/spp.c \
+ profiles/cups/hcrp.c
-cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ lib/libbluetooth-private.la
+profiles_cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ \
+ lib/libbluetooth-private.la
endif
diff --git a/cups/cups.h b/cups/cups.h
deleted file mode 100644
index f4e0c01..0000000
--- a/cups/cups.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2003-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
- *
- */
-
-enum { /**** Backend exit codes ****/
- CUPS_BACKEND_OK = 0, /* Job completed successfully */
- CUPS_BACKEND_FAILED = 1, /* Job failed, use error-policy */
- CUPS_BACKEND_AUTH_REQUIRED = 2, /* Job failed, authentication required */
- CUPS_BACKEND_HOLD = 3, /* Job failed, hold job */
- CUPS_BACKEND_STOP = 4, /* Job failed, stop queue */
- CUPS_BACKEND_CANCEL = 5, /* Job failed, cancel job */
- CUPS_BACKEND_RETRY = 6, /* Failure requires us to retry (BlueZ specific) */
-};
-
-int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel);
-int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm);
-
-int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class);
-int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class);
diff --git a/cups/hcrp.c b/cups/hcrp.c
deleted file mode 100644
index a93dda0..0000000
--- a/cups/hcrp.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2003-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 <string.h>
-#include <signal.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <netinet/in.h>
-
-#include "cups.h"
-
-#define HCRP_PDU_CREDIT_GRANT 0x0001
-#define HCRP_PDU_CREDIT_REQUEST 0x0002
-#define HCRP_PDU_GET_LPT_STATUS 0x0005
-
-#define HCRP_STATUS_FEATURE_UNSUPPORTED 0x0000
-#define HCRP_STATUS_SUCCESS 0x0001
-#define HCRP_STATUS_CREDIT_SYNC_ERROR 0x0002
-#define HCRP_STATUS_GENERIC_FAILURE 0xffff
-
-struct hcrp_pdu_hdr {
- uint16_t pid;
- uint16_t tid;
- uint16_t plen;
-} __attribute__ ((packed));
-#define HCRP_PDU_HDR_SIZE 6
-
-struct hcrp_credit_grant_cp {
- uint32_t credit;
-} __attribute__ ((packed));
-#define HCRP_CREDIT_GRANT_CP_SIZE 4
-
-struct hcrp_credit_grant_rp {
- uint16_t status;
-} __attribute__ ((packed));
-#define HCRP_CREDIT_GRANT_RP_SIZE 2
-
-struct hcrp_credit_request_rp {
- uint16_t status;
- uint32_t credit;
-} __attribute__ ((packed));
-#define HCRP_CREDIT_REQUEST_RP_SIZE 6
-
-struct hcrp_get_lpt_status_rp {
- uint16_t status;
- uint8_t lpt_status;
-} __attribute__ ((packed));
-#define HCRP_GET_LPT_STATUS_RP_SIZE 3
-
-static int hcrp_credit_grant(int sk, uint16_t tid, uint32_t credit)
-{
- struct hcrp_pdu_hdr hdr;
- struct hcrp_credit_grant_cp cp;
- struct hcrp_credit_grant_rp rp;
- unsigned char buf[128];
- int len;
-
- hdr.pid = htons(HCRP_PDU_CREDIT_GRANT);
- hdr.tid = htons(tid);
- hdr.plen = htons(HCRP_CREDIT_GRANT_CP_SIZE);
- cp.credit = credit;
- memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
- memcpy(buf + HCRP_PDU_HDR_SIZE, &cp, HCRP_CREDIT_GRANT_CP_SIZE);
- len = write(sk, buf, HCRP_PDU_HDR_SIZE + HCRP_CREDIT_GRANT_CP_SIZE);
- if (len < 0)
- return len;
-
- len = read(sk, buf, sizeof(buf));
- if (len < 0)
- return len;
-
- memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
- memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_GRANT_RP_SIZE);
-
- if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
- errno = EIO;
- return -1;
- }
-
- return 0;
-}
-
-static int hcrp_credit_request(int sk, uint16_t tid, uint32_t *credit)
-{
- struct hcrp_pdu_hdr hdr;
- struct hcrp_credit_request_rp rp;
- unsigned char buf[128];
- int len;
-
- hdr.pid = htons(HCRP_PDU_CREDIT_REQUEST);
- hdr.tid = htons(tid);
- hdr.plen = htons(0);
- memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
- len = write(sk, buf, HCRP_PDU_HDR_SIZE);
- if (len < 0)
- return len;
-
- len = read(sk, buf, sizeof(buf));
- if (len < 0)
- return len;
-
- memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
- memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_REQUEST_RP_SIZE);
-
- if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
- errno = EIO;
- return -1;
- }
-
- if (credit)
- *credit = ntohl(rp.credit);
-
- return 0;
-}
-
-static int hcrp_get_lpt_status(int sk, uint16_t tid, uint8_t *lpt_status)
-{
- struct hcrp_pdu_hdr hdr;
- struct hcrp_get_lpt_status_rp rp;
- unsigned char buf[128];
- int len;
-
- hdr.pid = htons(HCRP_PDU_GET_LPT_STATUS);
- hdr.tid = htons(tid);
- hdr.plen = htons(0);
- memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
- len = write(sk, buf, HCRP_PDU_HDR_SIZE);
- if (len < 0)
- return len;
-
- len = read(sk, buf, sizeof(buf));
- if (len < 0)
- return len;
-
- memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
- memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_GET_LPT_STATUS_RP_SIZE);
-
- if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
- errno = EIO;
- return -1;
- }
-
- if (lpt_status)
- *lpt_status = rp.lpt_status;
-
- return 0;
-}
-
-static inline int hcrp_get_next_tid(int tid)
-{
- if (tid > 0xf000)
- return 0;
- else
- return tid + 1;
-}
-
-int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class)
-{
- struct sockaddr_l2 addr;
- struct l2cap_options opts;
- socklen_t size;
- unsigned char buf[2048];
- int i, ctrl_sk, data_sk, count, len, timeout = 0;
- unsigned int mtu;
- uint8_t status;
- uint16_t tid = 0;
- uint32_t tmp, credit = 0;
-
- if ((ctrl_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
- perror("ERROR: Can't create socket");
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, src);
-
- if (bind(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("ERROR: Can't bind socket");
- close(ctrl_sk);
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, dst);
- addr.l2_psm = htobs(ctrl_psm);
-
- if (connect(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("ERROR: Can't connect to device");
- close(ctrl_sk);
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- if ((data_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
- perror("ERROR: Can't create socket");
- close(ctrl_sk);
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, src);
-
- if (bind(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("ERROR: Can't bind socket");
- close(data_sk);
- close(ctrl_sk);
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.l2_family = AF_BLUETOOTH;
- bacpy(&addr.l2_bdaddr, dst);
- addr.l2_psm = htobs(data_psm);
-
- if (connect(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("ERROR: Can't connect to device");
- close(data_sk);
- close(ctrl_sk);
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- fputs("STATE: -connecting-to-device\n", stderr);
-
- memset(&opts, 0, sizeof(opts));
- size = sizeof(opts);
-
- if (getsockopt(data_sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) {
- perror("ERROR: Can't get socket options");
- close(data_sk);
- close(ctrl_sk);
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- mtu = opts.omtu;
-
- /* Ignore SIGTERM signals if printing from stdin */
- if (fd == 0) {
-#ifdef HAVE_SIGSET
- sigset(SIGTERM, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
- memset(&action, 0, sizeof(action));
- sigemptyset(&action.sa_mask);
- action.sa_handler = SIG_IGN;
- sigaction(SIGTERM, &action, NULL);
-#else
- signal(SIGTERM, SIG_IGN);
-#endif /* HAVE_SIGSET */
- }
-
- tid = hcrp_get_next_tid(tid);
- if (hcrp_credit_grant(ctrl_sk, tid, 0) < 0) {
- fprintf(stderr, "ERROR: Can't grant initial credits\n");
- close(data_sk);
- close(ctrl_sk);
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- for (i = 0; i < copies; i++) {
-
- if (fd != 0) {
- fprintf(stderr, "PAGE: 1 1\n");
- lseek(fd, 0, SEEK_SET);
- }
-
- while (1) {
- if (credit < mtu) {
- tid = hcrp_get_next_tid(tid);
- if (!hcrp_credit_request(ctrl_sk, tid, &tmp)) {
- credit += tmp;
- timeout = 0;
- }
- }
-
- if (!credit) {
- if (timeout++ > 300) {
- tid = hcrp_get_next_tid(tid);
- if (!hcrp_get_lpt_status(ctrl_sk, tid, &status))
- fprintf(stderr, "ERROR: LPT status 0x%02x\n", status);
- break;
- }
-
- sleep(1);
- continue;
- }
-
- count = read(fd, buf, (credit > mtu) ? mtu : credit);
- if (count <= 0)
- break;
-
- len = write(data_sk, buf, count);
- if (len < 0) {
- perror("ERROR: Error writing to device");
- close(data_sk);
- close(ctrl_sk);
- return CUPS_BACKEND_FAILED;
- }
-
- if (len != count)
- fprintf(stderr, "ERROR: Can't send complete data\n");
-
- credit -= len;
- }
-
- }
-
- close(data_sk);
- close(ctrl_sk);
-
- return CUPS_BACKEND_OK;
-}
diff --git a/cups/main.c b/cups/main.c
deleted file mode 100644
index a884c6e..0000000
--- a/cups/main.c
+++ /dev/null
@@ -1,896 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2003-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 <signal.h>
-#include <sys/socket.h>
-#include <glib.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <gdbus.h>
-
-#include "cups.h"
-
-struct cups_device {
- char *bdaddr;
- char *name;
- char *id;
-};
-
-static GSList *device_list = NULL;
-static GMainLoop *loop = NULL;
-static DBusConnection *conn = NULL;
-static gboolean doing_disco = FALSE;
-
-#define ATTRID_1284ID 0x0300
-
-struct context_data {
- gboolean found;
- char *id;
-};
-
-static void element_start(GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **attribute_names,
- const gchar **attribute_values,
- gpointer user_data, GError **err)
-{
- struct context_data *ctx_data = user_data;
-
- if (!strcmp(element_name, "record"))
- return;
-
- if (!strcmp(element_name, "attribute")) {
- int i;
- for (i = 0; attribute_names[i]; i++) {
- if (strcmp(attribute_names[i], "id") != 0)
- continue;
- if (strtol(attribute_values[i], 0, 0) == ATTRID_1284ID)
- ctx_data->found = TRUE;
- break;
- }
- return;
- }
-
- if (ctx_data->found && !strcmp(element_name, "text")) {
- int i;
- for (i = 0; attribute_names[i]; i++) {
- if (!strcmp(attribute_names[i], "value")) {
- ctx_data->id = g_strdup(attribute_values[i] + 2);
- ctx_data->found = FALSE;
- }
- }
- }
-}
-
-static GMarkupParser parser = {
- element_start, NULL, NULL, NULL, NULL
-};
-
-static char *sdp_xml_parse_record(const char *data)
-{
- GMarkupParseContext *ctx;
- struct context_data ctx_data;
- int size;
-
- size = strlen(data);
- ctx_data.found = FALSE;
- ctx_data.id = NULL;
- ctx = g_markup_parse_context_new(&parser, 0, &ctx_data, NULL);
-
- if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
- g_markup_parse_context_free(ctx);
- g_free(ctx_data.id);
- return NULL;
- }
-
- g_markup_parse_context_free(ctx);
-
- return ctx_data.id;
-}
-
-static char *device_get_ieee1284_id(const char *adapter, const char *device)
-{
- DBusMessage *message, *reply;
- DBusMessageIter iter, reply_iter;
- DBusMessageIter reply_iter_entry;
- const char *hcr_print = "00001126-0000-1000-8000-00805f9b34fb";
- const char *xml;
- char *id = NULL;
-
- /* Look for the service handle of the HCRP service */
- message = dbus_message_new_method_call("org.bluez", device,
- "org.bluez.Device",
- "DiscoverServices");
- dbus_message_iter_init_append(message, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hcr_print);
-
- reply = dbus_connection_send_with_reply_and_block(conn,
- message, -1, NULL);
-
- dbus_message_unref(message);
-
- if (!reply)
- return NULL;
-
- dbus_message_iter_init(reply, &reply_iter);
-
- if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
- dbus_message_unref(reply);
- return NULL;
- }
-
- dbus_message_iter_recurse(&reply_iter, &reply_iter_entry);
-
- /* Hopefully we only get one handle, or take a punt */
- while (dbus_message_iter_get_arg_type(&reply_iter_entry) ==
- DBUS_TYPE_DICT_ENTRY) {
- guint32 key;
- DBusMessageIter dict_entry;
-
- dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
-
- /* Key ? */
- dbus_message_iter_get_basic(&dict_entry, &key);
- if (!key) {
- dbus_message_iter_next(&reply_iter_entry);
- continue;
- }
-
- /* Try to get the value */
- if (!dbus_message_iter_next(&dict_entry)) {
- dbus_message_iter_next(&reply_iter_entry);
- continue;
- }
-
- dbus_message_iter_get_basic(&dict_entry, &xml);
-
- id = sdp_xml_parse_record(xml);
- if (id != NULL)
- break;
- dbus_message_iter_next(&reply_iter_entry);
- }
-
- dbus_message_unref(reply);
-
- return id;
-}
-
-static void print_printer_details(const char *name, const char *bdaddr,
- const char *id)
-{
- char *uri, *escaped;
-
- escaped = g_strdelimit(g_strdup(name), "\"", '\'');
- uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
- bdaddr[0], bdaddr[1],
- bdaddr[3], bdaddr[4],
- bdaddr[6], bdaddr[7],
- bdaddr[9], bdaddr[10],
- bdaddr[12], bdaddr[13],
- bdaddr[15], bdaddr[16]);
- printf("direct %s \"%s\" \"%s (Bluetooth)\"", uri, escaped, escaped);
- if (id != NULL)
- printf(" \"%s\"\n", id);
- else
- printf("\n");
- g_free(escaped);
- g_free(uri);
-}
-
-static void add_device_to_list(const char *name, const char *bdaddr,
- const char *id)
-{
- struct cups_device *device;
- GSList *l;
-
- /* Look for the device in the list */
- for (l = device_list; l != NULL; l = l->next) {
- device = (struct cups_device *) l->data;
-
- if (strcmp(device->bdaddr, bdaddr) == 0) {
- if (device->name != name) {
- g_free(device->name);
- device->name = g_strdup(name);
- }
- g_free(device->id);
- device->id = g_strdup(id);
- return;
- }
- }
-
- /* Or add it to the list if it's not there */
- device = g_new0(struct cups_device, 1);
- device->bdaddr = g_strdup(bdaddr);
- device->name = g_strdup(name);
- device->id = g_strdup(id);
-
- device_list = g_slist_prepend(device_list, device);
- print_printer_details(device->name, device->bdaddr, device->id);
-}
-
-static gboolean parse_device_properties(DBusMessageIter *reply_iter,
- char **name, char **bdaddr)
-{
- guint32 class = 0;
- DBusMessageIter reply_iter_entry;
-
- if (dbus_message_iter_get_arg_type(reply_iter) != DBUS_TYPE_ARRAY)
- return FALSE;
-
- dbus_message_iter_recurse(reply_iter, &reply_iter_entry);
-
- while (dbus_message_iter_get_arg_type(&reply_iter_entry) ==
- DBUS_TYPE_DICT_ENTRY) {
- const char *key;
- DBusMessageIter dict_entry, iter_dict_val;
-
- dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
-
- /* Key == Class ? */
- dbus_message_iter_get_basic(&dict_entry, &key);
- if (!key) {
- dbus_message_iter_next(&reply_iter_entry);
- continue;
- }
-
- if (strcmp(key, "Class") != 0 &&
- strcmp(key, "Alias") != 0 &&
- strcmp(key, "Address") != 0) {
- dbus_message_iter_next(&reply_iter_entry);
- continue;
- }
-
- /* Try to get the value */
- if (!dbus_message_iter_next(&dict_entry)) {
- dbus_message_iter_next(&reply_iter_entry);
- continue;
- }
- dbus_message_iter_recurse(&dict_entry, &iter_dict_val);
- if (strcmp(key, "Class") == 0) {
- dbus_message_iter_get_basic(&iter_dict_val, &class);
- } else {
- const char *value;
- dbus_message_iter_get_basic(&iter_dict_val, &value);
- if (strcmp(key, "Alias") == 0) {
- *name = g_strdup(value);
- } else if (bdaddr) {
- *bdaddr = g_strdup(value);
- }
- }
- dbus_message_iter_next(&reply_iter_entry);
- }
-
- if (class == 0)
- return FALSE;
- if (((class & 0x1f00) >> 8) == 0x06 && (class & 0x80))
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean device_is_printer(const char *adapter, const char *device_path, char **name, char **bdaddr)
-{
- DBusMessage *message, *reply;
- DBusMessageIter reply_iter;
- gboolean retval;
-
- message = dbus_message_new_method_call("org.bluez", device_path,
- "org.bluez.Device",
- "GetProperties");
-
- reply = dbus_connection_send_with_reply_and_block(conn,
- message, -1, NULL);
-
- dbus_message_unref(message);
-
- if (!reply)
- return FALSE;
-
- dbus_message_iter_init(reply, &reply_iter);
-
- retval = parse_device_properties(&reply_iter, name, bdaddr);
-
- dbus_message_unref(reply);
-
- return retval;
-}
-
-static void remote_device_found(const char *adapter, const char *bdaddr,
- const char *name)
-{
- DBusMessage *message, *reply, *adapter_reply;
- DBusMessageIter iter;
- char *object_path = NULL;
- char *id;
-
- adapter_reply = NULL;
-
- if (adapter == NULL) {
- message = dbus_message_new_method_call("org.bluez", "/",
- "org.bluez.Manager",
- "DefaultAdapter");
-
- adapter_reply = dbus_connection_send_with_reply_and_block(conn,
- message, -1, NULL);
-
- dbus_message_unref(message);
-
- if (!adapter_reply)
- return;
-
- if (dbus_message_get_args(adapter_reply, NULL,
- DBUS_TYPE_OBJECT_PATH, &adapter,
- DBUS_TYPE_INVALID) == FALSE) {
- dbus_message_unref(adapter_reply);
- return;
- }
- }
-
- message = dbus_message_new_method_call("org.bluez", adapter,
- "org.bluez.Adapter",
- "FindDevice");
- dbus_message_iter_init_append(message, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
-
- if (adapter_reply != NULL)
- dbus_message_unref(adapter_reply);
-
- reply = dbus_connection_send_with_reply_and_block(conn,
- message, -1, NULL);
-
- dbus_message_unref(message);
-
- if (!reply) {
- message = dbus_message_new_method_call("org.bluez", adapter,
- "org.bluez.Adapter",
- "CreateDevice");
- dbus_message_iter_init_append(message, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
-
- reply = dbus_connection_send_with_reply_and_block(conn,
- message, -1, NULL);
-
- dbus_message_unref(message);
-
- if (!reply)
- return;
- }
-
- if (dbus_message_get_args(reply, NULL,
- DBUS_TYPE_OBJECT_PATH, &object_path,
- DBUS_TYPE_INVALID) == FALSE) {
- dbus_message_unref(reply);
- return;
- }
-
- id = device_get_ieee1284_id(adapter, object_path);
- add_device_to_list(name, bdaddr, id);
- g_free(id);
-
- dbus_message_unref(reply);
-}
-
-static void discovery_completed(void)
-{
- g_slist_free(device_list);
- device_list = NULL;
-
- g_main_loop_quit(loop);
-}
-
-static void remote_device_disappeared(const char *bdaddr)
-{
- GSList *l;
-
- for (l = device_list; l != NULL; l = l->next) {
- struct cups_device *device = l->data;
-
- if (strcmp(device->bdaddr, bdaddr) == 0) {
- g_free(device->name);
- g_free(device->bdaddr);
- g_free(device);
- device_list = g_slist_delete_link(device_list, l);
- return;
- }
- }
-}
-
-static gboolean list_known_printers(const char *adapter)
-{
- DBusMessageIter reply_iter, iter_array;
- DBusError error;
- DBusMessage *message, *reply;
-
- message = dbus_message_new_method_call("org.bluez", adapter,
- "org.bluez.Adapter",
- "ListDevices");
- if (message == NULL)
- return FALSE;
-
- dbus_error_init(&error);
- reply = dbus_connection_send_with_reply_and_block(conn, message,
- -1, &error);
-
- dbus_message_unref(message);
-
- if (dbus_error_is_set(&error))
- return FALSE;
-
- dbus_message_iter_init(reply, &reply_iter);
- if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
- dbus_message_unref(reply);
- return FALSE;
- }
-
- dbus_message_iter_recurse(&reply_iter, &iter_array);
- while (dbus_message_iter_get_arg_type(&iter_array) ==
- DBUS_TYPE_OBJECT_PATH) {
- const char *object_path;
- char *name = NULL;
- char *bdaddr = NULL;
-
- dbus_message_iter_get_basic(&iter_array, &object_path);
- if (device_is_printer(adapter, object_path, &name, &bdaddr)) {
- char *id;
-
- id = device_get_ieee1284_id(adapter, object_path);
- add_device_to_list(name, bdaddr, id);
- g_free(id);
- }
- g_free(name);
- g_free(bdaddr);
- dbus_message_iter_next(&iter_array);
- }
-
- dbus_message_unref(reply);
-
- return FALSE;
-}
-
-static DBusHandlerResult filter_func(DBusConnection *connection,
- DBusMessage *message, void *user_data)
-{
- if (dbus_message_is_signal(message, "org.bluez.Adapter",
- "DeviceFound")) {
- const char *adapter, *bdaddr;
- char *name;
- DBusMessageIter iter;
-
- dbus_message_iter_init(message, &iter);
- dbus_message_iter_get_basic(&iter, &bdaddr);
- dbus_message_iter_next(&iter);
-
- adapter = dbus_message_get_path(message);
- if (parse_device_properties(&iter, &name, NULL))
- remote_device_found(adapter, bdaddr, name);
- g_free (name);
- } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
- "DeviceDisappeared")) {
- const char *bdaddr;
-
- dbus_message_get_args(message, NULL,
- DBUS_TYPE_STRING, &bdaddr,
- DBUS_TYPE_INVALID);
- remote_device_disappeared(bdaddr);
- } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
- "PropertyChanged")) {
- DBusMessageIter iter, value_iter;
- const char *name;
- gboolean discovering;
-
- dbus_message_iter_init(message, &iter);
- dbus_message_iter_get_basic(&iter, &name);
- if (name == NULL || strcmp(name, "Discovering") != 0)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &value_iter);
- dbus_message_iter_get_basic(&value_iter, &discovering);
-
- if (discovering == FALSE && doing_disco) {
- doing_disco = FALSE;
- discovery_completed();
- }
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static gboolean list_printers(void)
-{
- /* 1. Connect to the bus
- * 2. Get the manager
- * 3. Get the default adapter
- * 4. Get a list of devices
- * 5. Get the class of each device
- * 6. Print the details from each printer device
- */
- DBusError error;
- dbus_bool_t hcid_exists;
- DBusMessage *reply, *message;
- DBusMessageIter reply_iter;
- char *adapter, *match;
-
- conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
- if (conn == NULL)
- return TRUE;
-
- dbus_error_init(&error);
- hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error);
- if (dbus_error_is_set(&error))
- return TRUE;
-
- if (!hcid_exists)
- return TRUE;
-
- /* Get the default adapter */
- message = dbus_message_new_method_call("org.bluez", "/",
- "org.bluez.Manager",
- "DefaultAdapter");
- if (message == NULL) {
- dbus_connection_unref(conn);
- return FALSE;
- }
-
- reply = dbus_connection_send_with_reply_and_block(conn,
- message, -1, &error);
-
- dbus_message_unref(message);
-
- if (dbus_error_is_set(&error)) {
- dbus_connection_unref(conn);
- /* No adapter */
- return TRUE;
- }
-
- dbus_message_iter_init(reply, &reply_iter);
- if (dbus_message_iter_get_arg_type(&reply_iter) !=
- DBUS_TYPE_OBJECT_PATH) {
- dbus_message_unref(reply);
- dbus_connection_unref(conn);
- return FALSE;
- }
-
- dbus_message_iter_get_basic(&reply_iter, &adapter);
- adapter = g_strdup(adapter);
- dbus_message_unref(reply);
-
- if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) {
- g_free(adapter);
- dbus_connection_unref(conn);
- return FALSE;
- }
-
-#define MATCH_FORMAT \
- "type='signal'," \
- "interface='org.bluez.Adapter'," \
- "sender='org.bluez'," \
- "path='%s'"
-
- match = g_strdup_printf(MATCH_FORMAT, adapter);
- dbus_bus_add_match(conn, match, &error);
- g_free(match);
-
- /* Add the the recent devices */
- list_known_printers(adapter);
-
- doing_disco = TRUE;
- message = dbus_message_new_method_call("org.bluez", adapter,
- "org.bluez.Adapter",
- "StartDiscovery");
-
- if (!dbus_connection_send_with_reply(conn, message, NULL, -1)) {
- dbus_message_unref(message);
- dbus_connection_unref(conn);
- g_free(adapter);
- return FALSE;
- }
- dbus_message_unref(message);
-
- loop = g_main_loop_new(NULL, TRUE);
- g_main_loop_run(loop);
-
- g_free(adapter);
- dbus_connection_unref(conn);
-
- return TRUE;
-}
-
-static gboolean print_ieee1284(const char *bdaddr)
-{
- DBusMessage *message, *reply, *adapter_reply;
- DBusMessageIter iter;
- char *object_path = NULL;
- char *adapter;
- char *id;
-
- adapter_reply = NULL;
-
- conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
- if (conn == NULL)
- return FALSE;
-
- message = dbus_message_new_method_call("org.bluez", "/",
- "org.bluez.Manager",
- "DefaultAdapter");
-
- adapter_reply = dbus_connection_send_with_reply_and_block(conn,
- message, -1, NULL);
-
- dbus_message_unref(message);
-
- if (!adapter_reply)
- return FALSE;
-
- if (dbus_message_get_args(adapter_reply, NULL,
- DBUS_TYPE_OBJECT_PATH, &adapter,
- DBUS_TYPE_INVALID) == FALSE) {
- dbus_message_unref(adapter_reply);
- return FALSE;
- }
-
- message = dbus_message_new_method_call("org.bluez", adapter,
- "org.bluez.Adapter",
- "FindDevice");
- dbus_message_iter_init_append(message, &iter);
- dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
-
- if (adapter_reply != NULL)
- dbus_message_unref(adapter_reply);
-
- reply = dbus_connection_send_with_reply_and_block(conn,
- message, -1, NULL);
-
- dbus_message_unref(message);
-
- if (!reply) {
- message = dbus_message_new_method_call("org.bluez", adapter,
- "org.bluez.Adapter",
- "CreateDevice");
- dbus_message_iter_init_append(message, &iter);
- dbus_message_iter_append_basic(&iter,
- DBUS_TYPE_STRING, &bdaddr);
-
- reply = dbus_connection_send_with_reply_and_block(conn,
- message, -1, NULL);
-
- dbus_message_unref(message);
-
- if (!reply)
- return FALSE;
- }
-
- if (dbus_message_get_args(reply, NULL,
- DBUS_TYPE_OBJECT_PATH, &object_path,
- DBUS_TYPE_INVALID) == FALSE) {
- dbus_message_unref(reply);
- return FALSE;
- }
-
- id = device_get_ieee1284_id(adapter, object_path);
- if (id == NULL) {
- dbus_message_unref(reply);
- return FALSE;
- }
- printf("%s", id);
- g_free(id);
-
- dbus_message_unref(reply);
-
- return TRUE;
-}
-
-/*
- * Usage: printer-uri job-id user title copies options [file]
- *
- */
-
-int main(int argc, char *argv[])
-{
- sdp_session_t *sdp;
- bdaddr_t bdaddr;
- unsigned short ctrl_psm, data_psm;
- uint8_t channel, b[6];
- char *ptr, str[3], device[18], service[12];
- const char *uri, *cups_class;
- int i, err, fd, copies, proto;
-
- /* Make sure status messages are not buffered */
- setbuf(stderr, NULL);
-
- /* Make sure output is not buffered */
- setbuf(stdout, NULL);
-
- /* Ignore SIGPIPE signals */
-#ifdef HAVE_SIGSET
- sigset(SIGPIPE, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
- memset(&action, 0, sizeof(action));
- action.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &action, NULL);
-#else
- signal(SIGPIPE, SIG_IGN);
-#endif /* HAVE_SIGSET */
-
- if (argc == 1) {
- if (list_printers() == TRUE)
- return CUPS_BACKEND_OK;
- else
- return CUPS_BACKEND_FAILED;
- } else if (argc == 3 && strcmp(argv[1], "--get-deviceid") == 0) {
- if (bachk(argv[2]) < 0) {
- fprintf(stderr, "Invalid Bluetooth address '%s'\n",
- argv[2]);
- return CUPS_BACKEND_FAILED;
- }
- if (print_ieee1284(argv[2]) == FALSE)
- return CUPS_BACKEND_FAILED;
- return CUPS_BACKEND_OK;
- }
-
- if (argc < 6 || argc > 7) {
- fprintf(stderr, "Usage: bluetooth job-id user title copies"
- " options [file]\n");
- fprintf(stderr, " bluetooth --get-deviceid [bdaddr]\n");
- return CUPS_BACKEND_FAILED;
- }
-
- if (argc == 6) {
- fd = 0;
- copies = 1;
- } else {
- if ((fd = open(argv[6], O_RDONLY)) < 0) {
- perror("ERROR: Unable to open print file");
- return CUPS_BACKEND_FAILED;
- }
- copies = atoi(argv[4]);
- }
-
- uri = getenv("DEVICE_URI");
- if (!uri)
- uri = argv[0];
-
- if (strncasecmp(uri, "bluetooth://", 12)) {
- fprintf(stderr, "ERROR: No device URI found\n");
- return CUPS_BACKEND_FAILED;
- }
-
- ptr = argv[0] + 12;
- for (i = 0; i < 6; i++) {
- strncpy(str, ptr, 2);
- b[i] = (uint8_t) strtol(str, NULL, 16);
- ptr += 2;
- }
- sprintf(device, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
- b[0], b[1], b[2], b[3], b[4], b[5]);
-
- str2ba(device, &bdaddr);
-
- ptr = strchr(ptr, '/');
- if (ptr) {
- strncpy(service, ptr + 1, 12);
-
- if (!strncasecmp(ptr + 1, "spp", 3))
- proto = 1;
- else if (!strncasecmp(ptr + 1, "hcrp", 4))
- proto = 2;
- else
- proto = 0;
- } else {
- strcpy(service, "auto");
- proto = 0;
- }
-
- cups_class = getenv("CLASS");
-
- fprintf(stderr,
- "DEBUG: %s device %s service %s fd %d copies %d class %s\n",
- argv[0], device, service, fd, copies,
- cups_class ? cups_class : "(none)");
-
- fputs("STATE: +connecting-to-device\n", stderr);
-
-service_search:
- sdp = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
- if (!sdp) {
- fprintf(stderr, "ERROR: Can't open Bluetooth connection\n");
- return CUPS_BACKEND_FAILED;
- }
-
- switch (proto) {
- case 1:
- err = sdp_search_spp(sdp, &channel);
- break;
- case 2:
- err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm);
- break;
- default:
- proto = 2;
- err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm);
- if (err) {
- proto = 1;
- err = sdp_search_spp(sdp, &channel);
- }
- break;
- }
-
- sdp_close(sdp);
-
- if (err) {
- if (cups_class) {
- fputs("INFO: Unable to contact printer, queuing on "
- "next printer in class...\n", stderr);
- sleep(5);
- return CUPS_BACKEND_FAILED;
- }
- sleep(20);
- fprintf(stderr, "ERROR: Can't get service information\n");
- goto service_search;
- }
-
-connect:
- switch (proto) {
- case 1:
- err = spp_print(BDADDR_ANY, &bdaddr, channel,
- fd, copies, cups_class);
- break;
- case 2:
- err = hcrp_print(BDADDR_ANY, &bdaddr, ctrl_psm, data_psm,
- fd, copies, cups_class);
- break;
- default:
- err = CUPS_BACKEND_FAILED;
- fprintf(stderr, "ERROR: Unsupported protocol\n");
- break;
- }
-
- if (err == CUPS_BACKEND_FAILED && cups_class) {
- fputs("INFO: Unable to contact printer, queuing on "
- "next printer in class...\n", stderr);
- sleep(5);
- return CUPS_BACKEND_FAILED;
- } else if (err == CUPS_BACKEND_RETRY) {
- sleep(20);
- goto connect;
- }
-
- if (fd != 0)
- close(fd);
-
- if (!err)
- fprintf(stderr, "INFO: Ready to print\n");
-
- return err;
-}
diff --git a/cups/sdp.c b/cups/sdp.c
deleted file mode 100644
index c7f17a4..0000000
--- a/cups/sdp.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2003-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 <signal.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include "cups.h"
-
-int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm)
-{
- sdp_list_t *srch, *attrs, *rsp;
- uuid_t svclass;
- uint16_t attr1, attr2;
- int err;
-
- if (!sdp)
- return -1;
-
- sdp_uuid16_create(&svclass, HCR_PRINT_SVCLASS_ID);
- srch = sdp_list_append(NULL, &svclass);
-
- attr1 = SDP_ATTR_PROTO_DESC_LIST;
- attrs = sdp_list_append(NULL, &attr1);
- attr2 = SDP_ATTR_ADD_PROTO_DESC_LIST;
- attrs = sdp_list_append(attrs, &attr2);
-
- err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
- if (err)
- return -1;
-
- for (; rsp; rsp = rsp->next) {
- sdp_record_t *rec = (sdp_record_t *) rsp->data;
- sdp_list_t *protos;
-
- if (!sdp_get_access_protos(rec, &protos)) {
- unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID);
- if (psm > 0) {
- *ctrl_psm = psm;
- }
- }
-
- if (!sdp_get_add_access_protos(rec, &protos)) {
- unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID);
- if (psm > 0 && *ctrl_psm > 0) {
- *data_psm = psm;
- return 0;
- }
- }
- }
-
- return -1;
-}
-
-int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel)
-{
- sdp_list_t *srch, *attrs, *rsp;
- uuid_t svclass;
- uint16_t attr;
- int err;
-
- if (!sdp)
- return -1;
-
- sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID);
- srch = sdp_list_append(NULL, &svclass);
-
- attr = SDP_ATTR_PROTO_DESC_LIST;
- attrs = sdp_list_append(NULL, &attr);
-
- err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
- if (err)
- return -1;
-
- for (; rsp; rsp = rsp->next) {
- sdp_record_t *rec = (sdp_record_t *) rsp->data;
- sdp_list_t *protos;
-
- if (!sdp_get_access_protos(rec, &protos)) {
- uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID);
- if (ch > 0) {
- *channel = ch;
- return 0;
- }
- }
- }
-
- return -1;
-}
diff --git a/cups/spp.c b/cups/spp.c
deleted file mode 100644
index d906ed2..0000000
--- a/cups/spp.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2003-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 <signal.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include "cups.h"
-
-int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class)
-{
- struct sockaddr_rc addr;
- unsigned char buf[2048];
- int i, sk, err, len;
-
- if ((sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
- perror("ERROR: Can't create socket");
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, src);
- addr.rc_channel = 0;
-
- if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("ERROR: Can't bind socket");
- close(sk);
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, dst);
- addr.rc_channel = channel;
-
- if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("ERROR: Can't connect to device");
- close(sk);
- if (cups_class)
- return CUPS_BACKEND_FAILED;
- else
- return CUPS_BACKEND_RETRY;
- }
-
- fputs("STATE: -connecting-to-device\n", stderr);
-
- /* Ignore SIGTERM signals if printing from stdin */
- if (fd == 0) {
-#ifdef HAVE_SIGSET
- sigset(SIGTERM, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
- memset(&action, 0, sizeof(action));
- sigemptyset(&action.sa_mask);
- action.sa_handler = SIG_IGN;
- sigaction(SIGTERM, &action, NULL);
-#else
- signal(SIGTERM, SIG_IGN);
-#endif /* HAVE_SIGSET */
- }
-
- for (i = 0; i < copies; i++) {
-
- if (fd != 0) {
- fprintf(stderr, "PAGE: 1 1\n");
- lseek(fd, 0, SEEK_SET);
- }
-
- while ((len = read(fd, buf, sizeof(buf))) > 0) {
- err = write(sk, buf, len);
- if (err < 0) {
- perror("ERROR: Error writing to device");
- close(sk);
- return CUPS_BACKEND_FAILED;
- }
- }
-
- }
-
- close(sk);
-
- return CUPS_BACKEND_OK;
-}
diff --git a/profiles/cups/cups.h b/profiles/cups/cups.h
new file mode 100644
index 0000000..f4e0c01
--- /dev/null
+++ b/profiles/cups/cups.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-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
+ *
+ */
+
+enum { /**** Backend exit codes ****/
+ CUPS_BACKEND_OK = 0, /* Job completed successfully */
+ CUPS_BACKEND_FAILED = 1, /* Job failed, use error-policy */
+ CUPS_BACKEND_AUTH_REQUIRED = 2, /* Job failed, authentication required */
+ CUPS_BACKEND_HOLD = 3, /* Job failed, hold job */
+ CUPS_BACKEND_STOP = 4, /* Job failed, stop queue */
+ CUPS_BACKEND_CANCEL = 5, /* Job failed, cancel job */
+ CUPS_BACKEND_RETRY = 6, /* Failure requires us to retry (BlueZ specific) */
+};
+
+int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel);
+int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm);
+
+int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class);
+int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class);
diff --git a/profiles/cups/hcrp.c b/profiles/cups/hcrp.c
new file mode 100644
index 0000000..a93dda0
--- /dev/null
+++ b/profiles/cups/hcrp.c
@@ -0,0 +1,368 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-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 <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <netinet/in.h>
+
+#include "cups.h"
+
+#define HCRP_PDU_CREDIT_GRANT 0x0001
+#define HCRP_PDU_CREDIT_REQUEST 0x0002
+#define HCRP_PDU_GET_LPT_STATUS 0x0005
+
+#define HCRP_STATUS_FEATURE_UNSUPPORTED 0x0000
+#define HCRP_STATUS_SUCCESS 0x0001
+#define HCRP_STATUS_CREDIT_SYNC_ERROR 0x0002
+#define HCRP_STATUS_GENERIC_FAILURE 0xffff
+
+struct hcrp_pdu_hdr {
+ uint16_t pid;
+ uint16_t tid;
+ uint16_t plen;
+} __attribute__ ((packed));
+#define HCRP_PDU_HDR_SIZE 6
+
+struct hcrp_credit_grant_cp {
+ uint32_t credit;
+} __attribute__ ((packed));
+#define HCRP_CREDIT_GRANT_CP_SIZE 4
+
+struct hcrp_credit_grant_rp {
+ uint16_t status;
+} __attribute__ ((packed));
+#define HCRP_CREDIT_GRANT_RP_SIZE 2
+
+struct hcrp_credit_request_rp {
+ uint16_t status;
+ uint32_t credit;
+} __attribute__ ((packed));
+#define HCRP_CREDIT_REQUEST_RP_SIZE 6
+
+struct hcrp_get_lpt_status_rp {
+ uint16_t status;
+ uint8_t lpt_status;
+} __attribute__ ((packed));
+#define HCRP_GET_LPT_STATUS_RP_SIZE 3
+
+static int hcrp_credit_grant(int sk, uint16_t tid, uint32_t credit)
+{
+ struct hcrp_pdu_hdr hdr;
+ struct hcrp_credit_grant_cp cp;
+ struct hcrp_credit_grant_rp rp;
+ unsigned char buf[128];
+ int len;
+
+ hdr.pid = htons(HCRP_PDU_CREDIT_GRANT);
+ hdr.tid = htons(tid);
+ hdr.plen = htons(HCRP_CREDIT_GRANT_CP_SIZE);
+ cp.credit = credit;
+ memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
+ memcpy(buf + HCRP_PDU_HDR_SIZE, &cp, HCRP_CREDIT_GRANT_CP_SIZE);
+ len = write(sk, buf, HCRP_PDU_HDR_SIZE + HCRP_CREDIT_GRANT_CP_SIZE);
+ if (len < 0)
+ return len;
+
+ len = read(sk, buf, sizeof(buf));
+ if (len < 0)
+ return len;
+
+ memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
+ memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_GRANT_RP_SIZE);
+
+ if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
+ errno = EIO;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int hcrp_credit_request(int sk, uint16_t tid, uint32_t *credit)
+{
+ struct hcrp_pdu_hdr hdr;
+ struct hcrp_credit_request_rp rp;
+ unsigned char buf[128];
+ int len;
+
+ hdr.pid = htons(HCRP_PDU_CREDIT_REQUEST);
+ hdr.tid = htons(tid);
+ hdr.plen = htons(0);
+ memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
+ len = write(sk, buf, HCRP_PDU_HDR_SIZE);
+ if (len < 0)
+ return len;
+
+ len = read(sk, buf, sizeof(buf));
+ if (len < 0)
+ return len;
+
+ memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
+ memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_REQUEST_RP_SIZE);
+
+ if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
+ errno = EIO;
+ return -1;
+ }
+
+ if (credit)
+ *credit = ntohl(rp.credit);
+
+ return 0;
+}
+
+static int hcrp_get_lpt_status(int sk, uint16_t tid, uint8_t *lpt_status)
+{
+ struct hcrp_pdu_hdr hdr;
+ struct hcrp_get_lpt_status_rp rp;
+ unsigned char buf[128];
+ int len;
+
+ hdr.pid = htons(HCRP_PDU_GET_LPT_STATUS);
+ hdr.tid = htons(tid);
+ hdr.plen = htons(0);
+ memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
+ len = write(sk, buf, HCRP_PDU_HDR_SIZE);
+ if (len < 0)
+ return len;
+
+ len = read(sk, buf, sizeof(buf));
+ if (len < 0)
+ return len;
+
+ memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
+ memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_GET_LPT_STATUS_RP_SIZE);
+
+ if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
+ errno = EIO;
+ return -1;
+ }
+
+ if (lpt_status)
+ *lpt_status = rp.lpt_status;
+
+ return 0;
+}
+
+static inline int hcrp_get_next_tid(int tid)
+{
+ if (tid > 0xf000)
+ return 0;
+ else
+ return tid + 1;
+}
+
+int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class)
+{
+ struct sockaddr_l2 addr;
+ struct l2cap_options opts;
+ socklen_t size;
+ unsigned char buf[2048];
+ int i, ctrl_sk, data_sk, count, len, timeout = 0;
+ unsigned int mtu;
+ uint8_t status;
+ uint16_t tid = 0;
+ uint32_t tmp, credit = 0;
+
+ if ((ctrl_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
+ perror("ERROR: Can't create socket");
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, src);
+
+ if (bind(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't bind socket");
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_psm = htobs(ctrl_psm);
+
+ if (connect(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't connect to device");
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ if ((data_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
+ perror("ERROR: Can't create socket");
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, src);
+
+ if (bind(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't bind socket");
+ close(data_sk);
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_psm = htobs(data_psm);
+
+ if (connect(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't connect to device");
+ close(data_sk);
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ memset(&opts, 0, sizeof(opts));
+ size = sizeof(opts);
+
+ if (getsockopt(data_sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) {
+ perror("ERROR: Can't get socket options");
+ close(data_sk);
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ mtu = opts.omtu;
+
+ /* Ignore SIGTERM signals if printing from stdin */
+ if (fd == 0) {
+#ifdef HAVE_SIGSET
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+ }
+
+ tid = hcrp_get_next_tid(tid);
+ if (hcrp_credit_grant(ctrl_sk, tid, 0) < 0) {
+ fprintf(stderr, "ERROR: Can't grant initial credits\n");
+ close(data_sk);
+ close(ctrl_sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ for (i = 0; i < copies; i++) {
+
+ if (fd != 0) {
+ fprintf(stderr, "PAGE: 1 1\n");
+ lseek(fd, 0, SEEK_SET);
+ }
+
+ while (1) {
+ if (credit < mtu) {
+ tid = hcrp_get_next_tid(tid);
+ if (!hcrp_credit_request(ctrl_sk, tid, &tmp)) {
+ credit += tmp;
+ timeout = 0;
+ }
+ }
+
+ if (!credit) {
+ if (timeout++ > 300) {
+ tid = hcrp_get_next_tid(tid);
+ if (!hcrp_get_lpt_status(ctrl_sk, tid, &status))
+ fprintf(stderr, "ERROR: LPT status 0x%02x\n", status);
+ break;
+ }
+
+ sleep(1);
+ continue;
+ }
+
+ count = read(fd, buf, (credit > mtu) ? mtu : credit);
+ if (count <= 0)
+ break;
+
+ len = write(data_sk, buf, count);
+ if (len < 0) {
+ perror("ERROR: Error writing to device");
+ close(data_sk);
+ close(ctrl_sk);
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (len != count)
+ fprintf(stderr, "ERROR: Can't send complete data\n");
+
+ credit -= len;
+ }
+
+ }
+
+ close(data_sk);
+ close(ctrl_sk);
+
+ return CUPS_BACKEND_OK;
+}
diff --git a/profiles/cups/main.c b/profiles/cups/main.c
new file mode 100644
index 0000000..a884c6e
--- /dev/null
+++ b/profiles/cups/main.c
@@ -0,0 +1,896 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-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 <signal.h>
+#include <sys/socket.h>
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <gdbus.h>
+
+#include "cups.h"
+
+struct cups_device {
+ char *bdaddr;
+ char *name;
+ char *id;
+};
+
+static GSList *device_list = NULL;
+static GMainLoop *loop = NULL;
+static DBusConnection *conn = NULL;
+static gboolean doing_disco = FALSE;
+
+#define ATTRID_1284ID 0x0300
+
+struct context_data {
+ gboolean found;
+ char *id;
+};
+
+static void element_start(GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data, GError **err)
+{
+ struct context_data *ctx_data = user_data;
+
+ if (!strcmp(element_name, "record"))
+ return;
+
+ if (!strcmp(element_name, "attribute")) {
+ int i;
+ for (i = 0; attribute_names[i]; i++) {
+ if (strcmp(attribute_names[i], "id") != 0)
+ continue;
+ if (strtol(attribute_values[i], 0, 0) == ATTRID_1284ID)
+ ctx_data->found = TRUE;
+ break;
+ }
+ return;
+ }
+
+ if (ctx_data->found && !strcmp(element_name, "text")) {
+ int i;
+ for (i = 0; attribute_names[i]; i++) {
+ if (!strcmp(attribute_names[i], "value")) {
+ ctx_data->id = g_strdup(attribute_values[i] + 2);
+ ctx_data->found = FALSE;
+ }
+ }
+ }
+}
+
+static GMarkupParser parser = {
+ element_start, NULL, NULL, NULL, NULL
+};
+
+static char *sdp_xml_parse_record(const char *data)
+{
+ GMarkupParseContext *ctx;
+ struct context_data ctx_data;
+ int size;
+
+ size = strlen(data);
+ ctx_data.found = FALSE;
+ ctx_data.id = NULL;
+ ctx = g_markup_parse_context_new(&parser, 0, &ctx_data, NULL);
+
+ if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
+ g_markup_parse_context_free(ctx);
+ g_free(ctx_data.id);
+ return NULL;
+ }
+
+ g_markup_parse_context_free(ctx);
+
+ return ctx_data.id;
+}
+
+static char *device_get_ieee1284_id(const char *adapter, const char *device)
+{
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, reply_iter;
+ DBusMessageIter reply_iter_entry;
+ const char *hcr_print = "00001126-0000-1000-8000-00805f9b34fb";
+ const char *xml;
+ char *id = NULL;
+
+ /* Look for the service handle of the HCRP service */
+ message = dbus_message_new_method_call("org.bluez", device,
+ "org.bluez.Device",
+ "DiscoverServices");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hcr_print);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init(reply, &reply_iter);
+
+ if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+ dbus_message_unref(reply);
+ return NULL;
+ }
+
+ dbus_message_iter_recurse(&reply_iter, &reply_iter_entry);
+
+ /* Hopefully we only get one handle, or take a punt */
+ while (dbus_message_iter_get_arg_type(&reply_iter_entry) ==
+ DBUS_TYPE_DICT_ENTRY) {
+ guint32 key;
+ DBusMessageIter dict_entry;
+
+ dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
+
+ /* Key ? */
+ dbus_message_iter_get_basic(&dict_entry, &key);
+ if (!key) {
+ dbus_message_iter_next(&reply_iter_entry);
+ continue;
+ }
+
+ /* Try to get the value */
+ if (!dbus_message_iter_next(&dict_entry)) {
+ dbus_message_iter_next(&reply_iter_entry);
+ continue;
+ }
+
+ dbus_message_iter_get_basic(&dict_entry, &xml);
+
+ id = sdp_xml_parse_record(xml);
+ if (id != NULL)
+ break;
+ dbus_message_iter_next(&reply_iter_entry);
+ }
+
+ dbus_message_unref(reply);
+
+ return id;
+}
+
+static void print_printer_details(const char *name, const char *bdaddr,
+ const char *id)
+{
+ char *uri, *escaped;
+
+ escaped = g_strdelimit(g_strdup(name), "\"", '\'');
+ uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
+ bdaddr[0], bdaddr[1],
+ bdaddr[3], bdaddr[4],
+ bdaddr[6], bdaddr[7],
+ bdaddr[9], bdaddr[10],
+ bdaddr[12], bdaddr[13],
+ bdaddr[15], bdaddr[16]);
+ printf("direct %s \"%s\" \"%s (Bluetooth)\"", uri, escaped, escaped);
+ if (id != NULL)
+ printf(" \"%s\"\n", id);
+ else
+ printf("\n");
+ g_free(escaped);
+ g_free(uri);
+}
+
+static void add_device_to_list(const char *name, const char *bdaddr,
+ const char *id)
+{
+ struct cups_device *device;
+ GSList *l;
+
+ /* Look for the device in the list */
+ for (l = device_list; l != NULL; l = l->next) {
+ device = (struct cups_device *) l->data;
+
+ if (strcmp(device->bdaddr, bdaddr) == 0) {
+ if (device->name != name) {
+ g_free(device->name);
+ device->name = g_strdup(name);
+ }
+ g_free(device->id);
+ device->id = g_strdup(id);
+ return;
+ }
+ }
+
+ /* Or add it to the list if it's not there */
+ device = g_new0(struct cups_device, 1);
+ device->bdaddr = g_strdup(bdaddr);
+ device->name = g_strdup(name);
+ device->id = g_strdup(id);
+
+ device_list = g_slist_prepend(device_list, device);
+ print_printer_details(device->name, device->bdaddr, device->id);
+}
+
+static gboolean parse_device_properties(DBusMessageIter *reply_iter,
+ char **name, char **bdaddr)
+{
+ guint32 class = 0;
+ DBusMessageIter reply_iter_entry;
+
+ if (dbus_message_iter_get_arg_type(reply_iter) != DBUS_TYPE_ARRAY)
+ return FALSE;
+
+ dbus_message_iter_recurse(reply_iter, &reply_iter_entry);
+
+ while (dbus_message_iter_get_arg_type(&reply_iter_entry) ==
+ DBUS_TYPE_DICT_ENTRY) {
+ const char *key;
+ DBusMessageIter dict_entry, iter_dict_val;
+
+ dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
+
+ /* Key == Class ? */
+ dbus_message_iter_get_basic(&dict_entry, &key);
+ if (!key) {
+ dbus_message_iter_next(&reply_iter_entry);
+ continue;
+ }
+
+ if (strcmp(key, "Class") != 0 &&
+ strcmp(key, "Alias") != 0 &&
+ strcmp(key, "Address") != 0) {
+ dbus_message_iter_next(&reply_iter_entry);
+ continue;
+ }
+
+ /* Try to get the value */
+ if (!dbus_message_iter_next(&dict_entry)) {
+ dbus_message_iter_next(&reply_iter_entry);
+ continue;
+ }
+ dbus_message_iter_recurse(&dict_entry, &iter_dict_val);
+ if (strcmp(key, "Class") == 0) {
+ dbus_message_iter_get_basic(&iter_dict_val, &class);
+ } else {
+ const char *value;
+ dbus_message_iter_get_basic(&iter_dict_val, &value);
+ if (strcmp(key, "Alias") == 0) {
+ *name = g_strdup(value);
+ } else if (bdaddr) {
+ *bdaddr = g_strdup(value);
+ }
+ }
+ dbus_message_iter_next(&reply_iter_entry);
+ }
+
+ if (class == 0)
+ return FALSE;
+ if (((class & 0x1f00) >> 8) == 0x06 && (class & 0x80))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean device_is_printer(const char *adapter, const char *device_path, char **name, char **bdaddr)
+{
+ DBusMessage *message, *reply;
+ DBusMessageIter reply_iter;
+ gboolean retval;
+
+ message = dbus_message_new_method_call("org.bluez", device_path,
+ "org.bluez.Device",
+ "GetProperties");
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return FALSE;
+
+ dbus_message_iter_init(reply, &reply_iter);
+
+ retval = parse_device_properties(&reply_iter, name, bdaddr);
+
+ dbus_message_unref(reply);
+
+ return retval;
+}
+
+static void remote_device_found(const char *adapter, const char *bdaddr,
+ const char *name)
+{
+ DBusMessage *message, *reply, *adapter_reply;
+ DBusMessageIter iter;
+ char *object_path = NULL;
+ char *id;
+
+ adapter_reply = NULL;
+
+ if (adapter == NULL) {
+ message = dbus_message_new_method_call("org.bluez", "/",
+ "org.bluez.Manager",
+ "DefaultAdapter");
+
+ adapter_reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!adapter_reply)
+ return;
+
+ if (dbus_message_get_args(adapter_reply, NULL,
+ DBUS_TYPE_OBJECT_PATH, &adapter,
+ DBUS_TYPE_INVALID) == FALSE) {
+ dbus_message_unref(adapter_reply);
+ return;
+ }
+ }
+
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "FindDevice");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+ if (adapter_reply != NULL)
+ dbus_message_unref(adapter_reply);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply) {
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "CreateDevice");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return;
+ }
+
+ if (dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_INVALID) == FALSE) {
+ dbus_message_unref(reply);
+ return;
+ }
+
+ id = device_get_ieee1284_id(adapter, object_path);
+ add_device_to_list(name, bdaddr, id);
+ g_free(id);
+
+ dbus_message_unref(reply);
+}
+
+static void discovery_completed(void)
+{
+ g_slist_free(device_list);
+ device_list = NULL;
+
+ g_main_loop_quit(loop);
+}
+
+static void remote_device_disappeared(const char *bdaddr)
+{
+ GSList *l;
+
+ for (l = device_list; l != NULL; l = l->next) {
+ struct cups_device *device = l->data;
+
+ if (strcmp(device->bdaddr, bdaddr) == 0) {
+ g_free(device->name);
+ g_free(device->bdaddr);
+ g_free(device);
+ device_list = g_slist_delete_link(device_list, l);
+ return;
+ }
+ }
+}
+
+static gboolean list_known_printers(const char *adapter)
+{
+ DBusMessageIter reply_iter, iter_array;
+ DBusError error;
+ DBusMessage *message, *reply;
+
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "ListDevices");
+ if (message == NULL)
+ return FALSE;
+
+ dbus_error_init(&error);
+ reply = dbus_connection_send_with_reply_and_block(conn, message,
+ -1, &error);
+
+ dbus_message_unref(message);
+
+ if (dbus_error_is_set(&error))
+ return FALSE;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+ dbus_message_unref(reply);
+ return FALSE;
+ }
+
+ dbus_message_iter_recurse(&reply_iter, &iter_array);
+ while (dbus_message_iter_get_arg_type(&iter_array) ==
+ DBUS_TYPE_OBJECT_PATH) {
+ const char *object_path;
+ char *name = NULL;
+ char *bdaddr = NULL;
+
+ dbus_message_iter_get_basic(&iter_array, &object_path);
+ if (device_is_printer(adapter, object_path, &name, &bdaddr)) {
+ char *id;
+
+ id = device_get_ieee1284_id(adapter, object_path);
+ add_device_to_list(name, bdaddr, id);
+ g_free(id);
+ }
+ g_free(name);
+ g_free(bdaddr);
+ dbus_message_iter_next(&iter_array);
+ }
+
+ dbus_message_unref(reply);
+
+ return FALSE;
+}
+
+static DBusHandlerResult filter_func(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "DeviceFound")) {
+ const char *adapter, *bdaddr;
+ char *name;
+ DBusMessageIter iter;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &bdaddr);
+ dbus_message_iter_next(&iter);
+
+ adapter = dbus_message_get_path(message);
+ if (parse_device_properties(&iter, &name, NULL))
+ remote_device_found(adapter, bdaddr, name);
+ g_free (name);
+ } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "DeviceDisappeared")) {
+ const char *bdaddr;
+
+ dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &bdaddr,
+ DBUS_TYPE_INVALID);
+ remote_device_disappeared(bdaddr);
+ } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "PropertyChanged")) {
+ DBusMessageIter iter, value_iter;
+ const char *name;
+ gboolean discovering;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &name);
+ if (name == NULL || strcmp(name, "Discovering") != 0)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &value_iter);
+ dbus_message_iter_get_basic(&value_iter, &discovering);
+
+ if (discovering == FALSE && doing_disco) {
+ doing_disco = FALSE;
+ discovery_completed();
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static gboolean list_printers(void)
+{
+ /* 1. Connect to the bus
+ * 2. Get the manager
+ * 3. Get the default adapter
+ * 4. Get a list of devices
+ * 5. Get the class of each device
+ * 6. Print the details from each printer device
+ */
+ DBusError error;
+ dbus_bool_t hcid_exists;
+ DBusMessage *reply, *message;
+ DBusMessageIter reply_iter;
+ char *adapter, *match;
+
+ conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+ if (conn == NULL)
+ return TRUE;
+
+ dbus_error_init(&error);
+ hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error);
+ if (dbus_error_is_set(&error))
+ return TRUE;
+
+ if (!hcid_exists)
+ return TRUE;
+
+ /* Get the default adapter */
+ message = dbus_message_new_method_call("org.bluez", "/",
+ "org.bluez.Manager",
+ "DefaultAdapter");
+ if (message == NULL) {
+ dbus_connection_unref(conn);
+ return FALSE;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, &error);
+
+ dbus_message_unref(message);
+
+ if (dbus_error_is_set(&error)) {
+ dbus_connection_unref(conn);
+ /* No adapter */
+ return TRUE;
+ }
+
+ dbus_message_iter_init(reply, &reply_iter);
+ if (dbus_message_iter_get_arg_type(&reply_iter) !=
+ DBUS_TYPE_OBJECT_PATH) {
+ dbus_message_unref(reply);
+ dbus_connection_unref(conn);
+ return FALSE;
+ }
+
+ dbus_message_iter_get_basic(&reply_iter, &adapter);
+ adapter = g_strdup(adapter);
+ dbus_message_unref(reply);
+
+ if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) {
+ g_free(adapter);
+ dbus_connection_unref(conn);
+ return FALSE;
+ }
+
+#define MATCH_FORMAT \
+ "type='signal'," \
+ "interface='org.bluez.Adapter'," \
+ "sender='org.bluez'," \
+ "path='%s'"
+
+ match = g_strdup_printf(MATCH_FORMAT, adapter);
+ dbus_bus_add_match(conn, match, &error);
+ g_free(match);
+
+ /* Add the the recent devices */
+ list_known_printers(adapter);
+
+ doing_disco = TRUE;
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "StartDiscovery");
+
+ if (!dbus_connection_send_with_reply(conn, message, NULL, -1)) {
+ dbus_message_unref(message);
+ dbus_connection_unref(conn);
+ g_free(adapter);
+ return FALSE;
+ }
+ dbus_message_unref(message);
+
+ loop = g_main_loop_new(NULL, TRUE);
+ g_main_loop_run(loop);
+
+ g_free(adapter);
+ dbus_connection_unref(conn);
+
+ return TRUE;
+}
+
+static gboolean print_ieee1284(const char *bdaddr)
+{
+ DBusMessage *message, *reply, *adapter_reply;
+ DBusMessageIter iter;
+ char *object_path = NULL;
+ char *adapter;
+ char *id;
+
+ adapter_reply = NULL;
+
+ conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+ if (conn == NULL)
+ return FALSE;
+
+ message = dbus_message_new_method_call("org.bluez", "/",
+ "org.bluez.Manager",
+ "DefaultAdapter");
+
+ adapter_reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!adapter_reply)
+ return FALSE;
+
+ if (dbus_message_get_args(adapter_reply, NULL,
+ DBUS_TYPE_OBJECT_PATH, &adapter,
+ DBUS_TYPE_INVALID) == FALSE) {
+ dbus_message_unref(adapter_reply);
+ return FALSE;
+ }
+
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "FindDevice");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+ if (adapter_reply != NULL)
+ dbus_message_unref(adapter_reply);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply) {
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "CreateDevice");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_STRING, &bdaddr);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return FALSE;
+ }
+
+ if (dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_INVALID) == FALSE) {
+ dbus_message_unref(reply);
+ return FALSE;
+ }
+
+ id = device_get_ieee1284_id(adapter, object_path);
+ if (id == NULL) {
+ dbus_message_unref(reply);
+ return FALSE;
+ }
+ printf("%s", id);
+ g_free(id);
+
+ dbus_message_unref(reply);
+
+ return TRUE;
+}
+
+/*
+ * Usage: printer-uri job-id user title copies options [file]
+ *
+ */
+
+int main(int argc, char *argv[])
+{
+ sdp_session_t *sdp;
+ bdaddr_t bdaddr;
+ unsigned short ctrl_psm, data_psm;
+ uint8_t channel, b[6];
+ char *ptr, str[3], device[18], service[12];
+ const char *uri, *cups_class;
+ int i, err, fd, copies, proto;
+
+ /* Make sure status messages are not buffered */
+ setbuf(stderr, NULL);
+
+ /* Make sure output is not buffered */
+ setbuf(stdout, NULL);
+
+ /* Ignore SIGPIPE signals */
+#ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+ if (argc == 1) {
+ if (list_printers() == TRUE)
+ return CUPS_BACKEND_OK;
+ else
+ return CUPS_BACKEND_FAILED;
+ } else if (argc == 3 && strcmp(argv[1], "--get-deviceid") == 0) {
+ if (bachk(argv[2]) < 0) {
+ fprintf(stderr, "Invalid Bluetooth address '%s'\n",
+ argv[2]);
+ return CUPS_BACKEND_FAILED;
+ }
+ if (print_ieee1284(argv[2]) == FALSE)
+ return CUPS_BACKEND_FAILED;
+ return CUPS_BACKEND_OK;
+ }
+
+ if (argc < 6 || argc > 7) {
+ fprintf(stderr, "Usage: bluetooth job-id user title copies"
+ " options [file]\n");
+ fprintf(stderr, " bluetooth --get-deviceid [bdaddr]\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ if (argc == 6) {
+ fd = 0;
+ copies = 1;
+ } else {
+ if ((fd = open(argv[6], O_RDONLY)) < 0) {
+ perror("ERROR: Unable to open print file");
+ return CUPS_BACKEND_FAILED;
+ }
+ copies = atoi(argv[4]);
+ }
+
+ uri = getenv("DEVICE_URI");
+ if (!uri)
+ uri = argv[0];
+
+ if (strncasecmp(uri, "bluetooth://", 12)) {
+ fprintf(stderr, "ERROR: No device URI found\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ ptr = argv[0] + 12;
+ for (i = 0; i < 6; i++) {
+ strncpy(str, ptr, 2);
+ b[i] = (uint8_t) strtol(str, NULL, 16);
+ ptr += 2;
+ }
+ sprintf(device, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ b[0], b[1], b[2], b[3], b[4], b[5]);
+
+ str2ba(device, &bdaddr);
+
+ ptr = strchr(ptr, '/');
+ if (ptr) {
+ strncpy(service, ptr + 1, 12);
+
+ if (!strncasecmp(ptr + 1, "spp", 3))
+ proto = 1;
+ else if (!strncasecmp(ptr + 1, "hcrp", 4))
+ proto = 2;
+ else
+ proto = 0;
+ } else {
+ strcpy(service, "auto");
+ proto = 0;
+ }
+
+ cups_class = getenv("CLASS");
+
+ fprintf(stderr,
+ "DEBUG: %s device %s service %s fd %d copies %d class %s\n",
+ argv[0], device, service, fd, copies,
+ cups_class ? cups_class : "(none)");
+
+ fputs("STATE: +connecting-to-device\n", stderr);
+
+service_search:
+ sdp = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
+ if (!sdp) {
+ fprintf(stderr, "ERROR: Can't open Bluetooth connection\n");
+ return CUPS_BACKEND_FAILED;
+ }
+
+ switch (proto) {
+ case 1:
+ err = sdp_search_spp(sdp, &channel);
+ break;
+ case 2:
+ err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm);
+ break;
+ default:
+ proto = 2;
+ err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm);
+ if (err) {
+ proto = 1;
+ err = sdp_search_spp(sdp, &channel);
+ }
+ break;
+ }
+
+ sdp_close(sdp);
+
+ if (err) {
+ if (cups_class) {
+ fputs("INFO: Unable to contact printer, queuing on "
+ "next printer in class...\n", stderr);
+ sleep(5);
+ return CUPS_BACKEND_FAILED;
+ }
+ sleep(20);
+ fprintf(stderr, "ERROR: Can't get service information\n");
+ goto service_search;
+ }
+
+connect:
+ switch (proto) {
+ case 1:
+ err = spp_print(BDADDR_ANY, &bdaddr, channel,
+ fd, copies, cups_class);
+ break;
+ case 2:
+ err = hcrp_print(BDADDR_ANY, &bdaddr, ctrl_psm, data_psm,
+ fd, copies, cups_class);
+ break;
+ default:
+ err = CUPS_BACKEND_FAILED;
+ fprintf(stderr, "ERROR: Unsupported protocol\n");
+ break;
+ }
+
+ if (err == CUPS_BACKEND_FAILED && cups_class) {
+ fputs("INFO: Unable to contact printer, queuing on "
+ "next printer in class...\n", stderr);
+ sleep(5);
+ return CUPS_BACKEND_FAILED;
+ } else if (err == CUPS_BACKEND_RETRY) {
+ sleep(20);
+ goto connect;
+ }
+
+ if (fd != 0)
+ close(fd);
+
+ if (!err)
+ fprintf(stderr, "INFO: Ready to print\n");
+
+ return err;
+}
diff --git a/profiles/cups/sdp.c b/profiles/cups/sdp.c
new file mode 100644
index 0000000..c7f17a4
--- /dev/null
+++ b/profiles/cups/sdp.c
@@ -0,0 +1,119 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-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 <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "cups.h"
+
+int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm)
+{
+ sdp_list_t *srch, *attrs, *rsp;
+ uuid_t svclass;
+ uint16_t attr1, attr2;
+ int err;
+
+ if (!sdp)
+ return -1;
+
+ sdp_uuid16_create(&svclass, HCR_PRINT_SVCLASS_ID);
+ srch = sdp_list_append(NULL, &svclass);
+
+ attr1 = SDP_ATTR_PROTO_DESC_LIST;
+ attrs = sdp_list_append(NULL, &attr1);
+ attr2 = SDP_ATTR_ADD_PROTO_DESC_LIST;
+ attrs = sdp_list_append(attrs, &attr2);
+
+ err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
+ if (err)
+ return -1;
+
+ for (; rsp; rsp = rsp->next) {
+ sdp_record_t *rec = (sdp_record_t *) rsp->data;
+ sdp_list_t *protos;
+
+ if (!sdp_get_access_protos(rec, &protos)) {
+ unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID);
+ if (psm > 0) {
+ *ctrl_psm = psm;
+ }
+ }
+
+ if (!sdp_get_add_access_protos(rec, &protos)) {
+ unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID);
+ if (psm > 0 && *ctrl_psm > 0) {
+ *data_psm = psm;
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel)
+{
+ sdp_list_t *srch, *attrs, *rsp;
+ uuid_t svclass;
+ uint16_t attr;
+ int err;
+
+ if (!sdp)
+ return -1;
+
+ sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID);
+ srch = sdp_list_append(NULL, &svclass);
+
+ attr = SDP_ATTR_PROTO_DESC_LIST;
+ attrs = sdp_list_append(NULL, &attr);
+
+ err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
+ if (err)
+ return -1;
+
+ for (; rsp; rsp = rsp->next) {
+ sdp_record_t *rec = (sdp_record_t *) rsp->data;
+ sdp_list_t *protos;
+
+ if (!sdp_get_access_protos(rec, &protos)) {
+ uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ if (ch > 0) {
+ *channel = ch;
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
diff --git a/profiles/cups/spp.c b/profiles/cups/spp.c
new file mode 100644
index 0000000..d906ed2
--- /dev/null
+++ b/profiles/cups/spp.c
@@ -0,0 +1,118 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2003-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 <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "cups.h"
+
+int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class)
+{
+ struct sockaddr_rc addr;
+ unsigned char buf[2048];
+ int i, sk, err, len;
+
+ if ((sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
+ perror("ERROR: Can't create socket");
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, src);
+ addr.rc_channel = 0;
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't bind socket");
+ close(sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, dst);
+ addr.rc_channel = channel;
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("ERROR: Can't connect to device");
+ close(sk);
+ if (cups_class)
+ return CUPS_BACKEND_FAILED;
+ else
+ return CUPS_BACKEND_RETRY;
+ }
+
+ fputs("STATE: -connecting-to-device\n", stderr);
+
+ /* Ignore SIGTERM signals if printing from stdin */
+ if (fd == 0) {
+#ifdef HAVE_SIGSET
+ sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGTERM, &action, NULL);
+#else
+ signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+ }
+
+ for (i = 0; i < copies; i++) {
+
+ if (fd != 0) {
+ fprintf(stderr, "PAGE: 1 1\n");
+ lseek(fd, 0, SEEK_SET);
+ }
+
+ while ((len = read(fd, buf, sizeof(buf))) > 0) {
+ err = write(sk, buf, len);
+ if (err < 0) {
+ perror("ERROR: Error writing to device");
+ close(sk);
+ return CUPS_BACKEND_FAILED;
+ }
+ }
+
+ }
+
+ close(sk);
+
+ return CUPS_BACKEND_OK;
+}
--
1.7.10.2
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH -v3 03/22] adapter: remove deprecated ListDevices() method
2012-07-04 8:17 ` [PATCH -v2 05/28] adapter: remove deprecated ListDevices() method Gustavo Padovan
@ 2012-07-04 12:31 ` Gustavo Padovan
0 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:31 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 -----------------------------------
test/test-attrib | 2 +-
test/test-device | 2 +-
test/test-health | 2 +-
test/test-health-sink | 2 +-
6 files changed, 4 insertions(+), 49 deletions(-)
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 916e941..176843b 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 eeba44d..a043366 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" }),
diff --git a/test/test-attrib b/test/test-attrib
index 52b399c..f83859d 100755
--- a/test/test-attrib
+++ b/test/test-attrib
@@ -46,7 +46,7 @@ if (len(args) < 1):
sys.exit(1)
if (args[0] == "list"):
- for path in adapter.ListDevices():
+ for path in adapter.GetProperties()["Devices"]:
device = dbus.Interface(bus.get_object("org.bluez", path),
"org.bluez.Device")
devprop = device.GetProperties()
diff --git a/test/test-device b/test/test-device
index 81a44f8..63a96d3 100755
--- a/test/test-device
+++ b/test/test-device
@@ -49,7 +49,7 @@ if (len(args) < 1):
sys.exit(1)
if (args[0] == "list"):
- for path in adapter.ListDevices():
+ for path in adapter.GetProperties()["Devices"]:
device = dbus.Interface(bus.get_object("org.bluez", path),
"org.bluez.Device")
properties = device.GetProperties()
diff --git a/test/test-health b/test/test-health
index f7d4241..307e880 100755
--- a/test/test-health
+++ b/test/test-health
@@ -157,7 +157,7 @@ while select == None:
adapter = dbus.Interface(bus.get_object("org.bluez", select),
"org.bluez.Adapter")
-devices = adapter.ListDevices()
+devices = adapter.GetProperties()["Devices"]
if len(devices) == 0:
print("No devices available")
diff --git a/test/test-health-sink b/test/test-health-sink
index ce7337a..7ee5e1a 100755
--- a/test/test-health-sink
+++ b/test/test-health-sink
@@ -47,7 +47,7 @@ while select == None:
adapter = dbus.Interface(bus.get_object("org.bluez", select),
"org.bluez.Adapter")
-devices = adapter.ListDevices()
+devices = adapter.GetProperties()["Devices"]
if len(devices) == 0:
print("No devices available")
--
1.7.10.2
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH -v3 04/22] manager: remove deprecated ListAdapters() method
2012-07-04 8:17 ` [PATCH -v2 04/28] sink: remove deprecated DBus method Gustavo Padovan
@ 2012-07-04 12:31 ` Gustavo Padovan
0 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo Padovan
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
---
src/manager.c | 33 ---------------------------------
test/list-devices | 3 +--
test/test-health | 2 +-
test/test-health-sink | 3 +--
4 files changed, 3 insertions(+), 38 deletions(-)
diff --git a/src/manager.c b/src/manager.c
index 1637657..4a39461 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_DEPRECATED_METHOD("ListAdapters",
- NULL, GDBUS_ARGS({ "adapters", "ao" }),
- list_adapters) },
{ }
};
diff --git a/test/list-devices b/test/list-devices
index 7ef6511..1683142 100755
--- a/test/list-devices
+++ b/test/list-devices
@@ -29,8 +29,7 @@ def extract_uuids(uuid_list):
list = list + val + " "
return list
-adapter_list = manager.ListAdapters()
-
+adapter_list = manager.GetProperties()["Adapters"]
for i in adapter_list:
adapter = dbus.Interface(bus.get_object("org.bluez", i),
"org.bluez.Adapter")
diff --git a/test/test-health b/test/test-health
index 307e880..a7df679 100755
--- a/test/test-health
+++ b/test/test-health
@@ -134,7 +134,7 @@ if not con:
manager = dbus.Interface(bus.get_object("org.bluez", "/"),
"org.bluez.Manager")
-adapters = manager.ListAdapters()
+adapters = manager.GetProperties()["Adapters"]
i = 1
for ad in adapters:
diff --git a/test/test-health-sink b/test/test-health-sink
index 7ee5e1a..333b2fb 100755
--- a/test/test-health-sink
+++ b/test/test-health-sink
@@ -24,8 +24,7 @@ print(app_path)
manager = dbus.Interface(bus.get_object("org.bluez", "/"),
"org.bluez.Manager")
-adapters = manager.ListAdapters()
-
+adapters = manager.GetProperties()["Adapters"]
i = 1
for ad in adapters:
print("%d. %s" % (i, ad))
--
1.7.10.2
^ permalink raw reply related [flat|nested] 25+ messages in thread
end of thread, other threads:[~2012-07-04 12:31 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-04 8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 02/28] remove the hciops plugin Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 03/28] headset: remove deprecated DBus methods Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 04/28] sink: remove deprecated DBus method Gustavo Padovan
2012-07-04 12:31 ` [PATCH -v3 04/22] manager: remove deprecated ListAdapters() method Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 05/28] adapter: remove deprecated ListDevices() method Gustavo Padovan
2012-07-04 12:31 ` [PATCH -v3 03/22] " Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 06/28] manager: remove deprecated ListAdapters() method Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 07/28] adapter: remove btd_adapter_encrypt_link() Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 08/28] adapter_ops: remove disable_cod_cache Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 09/28] manager: remove unused manager_add_adapter() Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 10/28] adapter: make restore powered work again Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 11/28] serial: remove SerialProxy interface Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 12/28] serial: remove unneeded headers include Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 13/28] input: remove unneeded header inclusions Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 14/28] serial: remove old way to connect to a serial port Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 15/28] emulator: move it to the tools folder Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 16/28] btmgmt: move to " Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 17/28] alert: move alert to profiles dir Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 18/28] deviceinfo: move to profiles folder Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 20/28] thermometer: move to the " Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 21/28] time: " Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 23/28] test: add test-audiosource Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 25/28] serial: move it to the profiles folder Gustavo Padovan
2012-07-04 8:17 ` [PATCH -v2 27/28] cups: move it to " Gustavo Padovan
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.