aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnderson Lizardo <anderson.lizardo@openbossa.org>2010-07-28 11:54:19 -0400
committerJohan Hedberg <johan.hedberg@nokia.com>2010-08-09 18:06:46 -0400
commitf1d7e6a7a91bd5d0140429e20a8e2c93b14594a7 (patch)
tree8c3f8649fc8fabc5e98d44305c09ddeba321aecf
parentfa7e72f64b88592fa6cfc4cfb8918d93f2c1fdbd (diff)
downloadbluez-f1d7e6a7a91bd5d0140429e20a8e2c93b14594a7.tar.gz
bluez-f1d7e6a7a91bd5d0140429e20a8e2c93b14594a7.tar.xz
bluez-f1d7e6a7a91bd5d0140429e20a8e2c93b14594a7.zip
gatttool: add support for L2CAP socket connection
Connect using L2CAP by default, and add a --unix/-u option to select the Unix socket (for local testing).
-rw-r--r--attrib/gatttool.c78
1 files changed, 75 insertions, 3 deletions
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 0f88acc6..bed14613 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -27,20 +27,86 @@
#include <errno.h>
#include <glib.h>
+#include <stdlib.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/socket.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
#define GATT_UNIX_PATH "/var/run/gatt"
+#define GATT_PSM 27
static gchar *opt_src = NULL;
static gchar *opt_dst = NULL;
static int opt_start = 0x0001;
static int opt_end = 0xffff;
+static gboolean opt_unix = FALSE;
static gboolean opt_primary = FALSE;
static gboolean opt_characteristics = FALSE;
static GMainLoop *event_loop;
+static int l2cap_connect(void)
+{
+ struct sockaddr_l2 addr;
+ bdaddr_t sba, dba;
+ int err, sk;
+
+ /* Remote device */
+ if (opt_dst == NULL) {
+ g_printerr("Remote Bluetooth address required\n");
+ return -EINVAL;
+ }
+
+ str2ba(opt_dst, &dba);
+
+ /* Local adapter */
+ if (opt_src != NULL) {
+ if (!strncmp(opt_src, "hci", 3))
+ hci_devba(atoi(opt_src + 3), &sba);
+ else
+ str2ba(opt_src, &sba);
+ g_free(opt_src);
+ } else
+ bacpy(&sba, BDADDR_ANY);
+
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sk < 0) {
+ err = errno;
+ g_printerr("L2CAP socket create failed: %s(%d)\n", strerror(err), err);
+ return -err;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, &sba);
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = errno;
+ g_printerr("L2CAP socket bind failed: %s(%d)\n", strerror(err), err);
+ close(sk);
+ return -err;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.l2_family = AF_BLUETOOTH;
+ bacpy(&addr.l2_bdaddr, &dba);
+ addr.l2_psm = htobs(GATT_PSM);
+
+ err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0) {
+ err = errno;
+ g_printerr("L2CAP socket connect failed: %s(%d)\n", strerror(err), err);
+ close(sk);
+ return -err;
+ }
+
+ return sk;
+}
+
static int unix_connect(const char *address)
{
struct sockaddr_un addr;
@@ -73,12 +139,16 @@ static gboolean primary(gpointer user_data)
{
int sk;
- /* FIXME: implement option to select between unix/btio socket */
- sk = unix_connect(GATT_UNIX_PATH);
+ if (opt_unix)
+ sk = unix_connect(GATT_UNIX_PATH);
+ else
+ sk = l2cap_connect();
if (sk < 0)
- return FALSE;
+ goto error;
/* FIXME: implement "discover all primary services */
+
+error:
g_main_loop_quit(event_loop);
return FALSE;
@@ -101,6 +171,8 @@ static GOptionEntry gatt_options[] = {
};
static GOptionEntry options[] = {
+ { "unix", 'u', 0, G_OPTION_ARG_NONE, &opt_unix,
+ "Connect to server using Unix socket" , NULL },
{ "adapter", 'i', 0, G_OPTION_ARG_STRING, &opt_src,
"Specify local adapter interface", "hciX" },
{ "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst,