* [PATCH -v3 01/19] headset: remove deprecated D-Bus methods
@ 2012-07-04 12:51 Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 02/19] sink: remove deprecated D-Bus method Gustavo Padovan
` (12 more replies)
0 siblings, 13 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 02/19] sink: remove deprecated D-Bus method
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 03/19] serial: remove SerialProxy interface Gustavo Padovan
` (11 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 03/19] serial: remove SerialProxy interface
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 02/19] sink: remove deprecated D-Bus method Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 04/19] serial: remove unneeded headers include Gustavo Padovan
` (10 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 04/19] serial: remove unneeded headers include
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 02/19] sink: remove deprecated D-Bus method Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 03/19] serial: remove SerialProxy interface Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 05/19] input: remove unneeded header inclusions Gustavo Padovan
` (9 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 05/19] input: remove unneeded header inclusions
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
` (2 preceding siblings ...)
2012-07-04 12:51 ` [PATCH -v3 04/19] serial: remove unneeded headers include Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 06/19] serial: remove old way to connect to a serial port Gustavo Padovan
` (8 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 06/19] serial: remove old way to connect to a serial port
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
` (3 preceding siblings ...)
2012-07-04 12:51 ` [PATCH -v3 05/19] input: remove unneeded header inclusions Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 07/19] emulator: move it to the tools folder Gustavo Padovan
` (7 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 07/19] emulator: move it to the tools folder
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
` (4 preceding siblings ...)
2012-07-04 12:51 ` [PATCH -v3 06/19] serial: remove old way to connect to a serial port Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 08/19] btmgmt: move to " Gustavo Padovan
` (6 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 08/19] btmgmt: move to tools folder
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
` (5 preceding siblings ...)
2012-07-04 12:51 ` [PATCH -v3 07/19] emulator: move it to the tools folder Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 09/19] alert: move alert to profiles dir Gustavo Padovan
` (5 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 09/19] alert: move alert to profiles dir
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
` (6 preceding siblings ...)
2012-07-04 12:51 ` [PATCH -v3 08/19] btmgmt: move to " Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 10/19] deviceinfo: move to profiles folder Gustavo Padovan
` (4 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 10/19] deviceinfo: move to profiles folder
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
` (7 preceding siblings ...)
2012-07-04 12:51 ` [PATCH -v3 09/19] alert: move alert to profiles dir Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 12/19] thermometer: move to the " Gustavo Padovan
` (3 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 12/19] thermometer: move to the profiles folder
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
` (8 preceding siblings ...)
2012-07-04 12:51 ` [PATCH -v3 10/19] deviceinfo: move to profiles folder Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 13/19] time: " Gustavo Padovan
` (2 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 13/19] time: move to the profiles folder
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
` (9 preceding siblings ...)
2012-07-04 12:51 ` [PATCH -v3 12/19] thermometer: move to the " Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 16/19] serial: move it " Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 18/19] cups: move it to " Gustavo Padovan
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 16/19] serial: move it to the profiles folder
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
` (10 preceding siblings ...)
2012-07-04 12:51 ` [PATCH -v3 13/19] time: " Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 18/19] cups: move it to " Gustavo Padovan
12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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] 15+ messages in thread
* [PATCH -v3 18/19] cups: move it to profiles folder
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
` (11 preceding siblings ...)
2012-07-04 12:51 ` [PATCH -v3 16/19] serial: move it " Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
2012-07-04 13:34 ` Marcel Holtmann
12 siblings, 1 reply; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 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 e4cf238..db2d844 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] 15+ messages in thread
* Re: [PATCH -v3 18/19] cups: move it to profiles folder
2012-07-04 12:51 ` [PATCH -v3 18/19] cups: move it to " Gustavo Padovan
@ 2012-07-04 13:34 ` Marcel Holtmann
0 siblings, 0 replies; 15+ messages in thread
From: Marcel Holtmann @ 2012-07-04 13:34 UTC (permalink / raw)
To: Gustavo Padovan; +Cc: linux-bluetooth, Gustavo Padovan
Hi Gustavo,
> ---
> 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
please stop moving things around until I agreed with any new directory
structure.
Regards
Marcel
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2012-07-04 13:34 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 02/19] sink: remove deprecated D-Bus method Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 03/19] serial: remove SerialProxy interface Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 04/19] serial: remove unneeded headers include Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 05/19] input: remove unneeded header inclusions Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 06/19] serial: remove old way to connect to a serial port Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 07/19] emulator: move it to the tools folder Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 08/19] btmgmt: move to " Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 09/19] alert: move alert to profiles dir Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 10/19] deviceinfo: move to profiles folder Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 12/19] thermometer: move to the " Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 13/19] time: " Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 16/19] serial: move it " Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 18/19] cups: move it to " Gustavo Padovan
2012-07-04 13:34 ` Marcel Holtmann
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.