linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ 1/7] shared/io: Add io_recv
@ 2017-10-24 13:24 Luiz Augusto von Dentz
  2017-10-24 13:24 ` [PATCH BlueZ 2/7] shared: Add initial code for 6LoWPAN Luiz Augusto von Dentz
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-24 13:24 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds io_recv for reading using different buffer pointed by iovec.
---
 src/shared/io-glib.c | 20 ++++++++++++++++++++
 src/shared/io.h      |  1 +
 2 files changed, 21 insertions(+)

diff --git a/src/shared/io-glib.c b/src/shared/io-glib.c
index 6687a6b28..3ea68ac4e 100644
--- a/src/shared/io-glib.c
+++ b/src/shared/io-glib.c
@@ -280,6 +280,26 @@ ssize_t io_send(struct io *io, const struct iovec *iov, int iovcnt)
 	return ret;
 }
 
+ssize_t io_recv(struct io *io, const struct iovec *iov, int iovcnt)
+{
+	int fd;
+	ssize_t ret;
+
+	if (!io || !io->channel)
+		return -ENOTCONN;
+
+	fd = io_get_fd(io);
+
+	do {
+		ret = readv(fd, iov, iovcnt);
+	} while (ret < 0 && errno == EINTR);
+
+	if (ret < 0)
+		return -errno;
+
+	return ret;
+}
+
 bool io_shutdown(struct io *io)
 {
 	if (!io || !io->channel)
diff --git a/src/shared/io.h b/src/shared/io.h
index 8bc1111d0..14f0034cf 100644
--- a/src/shared/io.h
+++ b/src/shared/io.h
@@ -35,6 +35,7 @@ int io_get_fd(struct io *io);
 bool io_set_close_on_destroy(struct io *io, bool do_close);
 
 ssize_t io_send(struct io *io, const struct iovec *iov, int iovcnt);
+ssize_t io_recv(struct io *io, const struct iovec *iov, int iovcnt);
 bool io_shutdown(struct io *io);
 
 typedef bool (*io_callback_func_t)(struct io *io, void *user_data);
-- 
2.13.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 2/7] shared: Add initial code for 6LoWPAN
  2017-10-24 13:24 [PATCH BlueZ 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
@ 2017-10-24 13:24 ` Luiz Augusto von Dentz
  2017-10-24 13:24 ` [PATCH BlueZ 3/7] unit: Add initial test for bt_6lo Luiz Augusto von Dentz
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-24 13:24 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This introduces struct bt_6lo to interface with 6LoWPAN kernel
driver.
---
 Makefile.am      |   2 +-
 src/shared/6lo.c | 523 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/6lo.h |  40 +++++
 3 files changed, 564 insertions(+), 1 deletion(-)
 create mode 100644 src/shared/6lo.c
 create mode 100644 src/shared/6lo.h

diff --git a/Makefile.am b/Makefile.am
index 8faabf44b..bb5a77408 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -119,7 +119,7 @@ shared_sources = src/shared/io.h src/shared/timeout.h \
 			src/shared/gatt-server.h src/shared/gatt-server.c \
 			src/shared/gatt-db.h src/shared/gatt-db.c \
 			src/shared/gap.h src/shared/gap.c \
-			src/shared/tty.h
+			src/shared/tty.h src/shared/6lo.h src/shared/6lo.c
 
 src_libshared_glib_la_SOURCES = $(shared_sources) \
 				src/shared/io-glib.c \
diff --git a/src/shared/6lo.c b/src/shared/6lo.c
new file mode 100644
index 000000000..3a0bf5678
--- /dev/null
+++ b/src/shared/6lo.c
@@ -0,0 +1,523 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2017  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; 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 <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_tun.h>
+#include <net/ethernet.h>
+#include <arpa/inet.h>
+#include <netinet/ip6.h>
+
+#include "src/shared/io.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "src/shared/6lo.h"
+
+#define DEV_6LO "/dev/net/tun"
+#define IFF_6LO 0x0040
+#define IFF_6LO_FLAGS IFF_TAP | IFF_6LO | IFF_NO_PI
+#define IFMTU ETHERMTU /* TUN/TAP doesn't seem to allow changing this */
+
+struct bt_6lo_chan {
+	struct bt_6lo_if *iface;
+	struct ether_addr addr;
+	struct io *io;
+};
+
+struct bt_6lo_if {
+	struct bt_6lo *lo;
+	struct ether_addr addr;
+	char name[IFNAMSIZ];
+	unsigned int index;
+	uint8_t buf[IFMTU];
+	struct io *io;
+	struct queue *channels;
+};
+
+struct bt_6lo {
+	int ref_count;
+	int fd;
+	struct queue *ifs;
+
+	bt_6lo_debug_func_t debug_callback;
+	bt_6lo_destroy_func_t debug_destroy;
+	void *debug_data;
+};
+
+static void chan_free(void *data)
+{
+	struct bt_6lo_chan *chan = data;
+
+	io_destroy(chan->io);
+	free(chan);
+}
+
+static void if_free(void *data)
+{
+	struct bt_6lo_if *iface = data;
+
+	queue_destroy(iface->channels, chan_free);
+	io_destroy(iface->io);
+	free(iface);
+}
+
+static void lo_free(struct bt_6lo *lo)
+{
+	if (lo->fd > 0)
+		close(lo->fd);
+
+	queue_destroy(lo->ifs, if_free);
+	free(lo);
+}
+
+struct bt_6lo *bt_6lo_new_default(void)
+{
+	int fd;
+	unsigned int flags;
+
+	if ((fd = open(DEV_6LO, O_RDWR)) < 0)
+		return NULL;
+
+	/* read back flags to check if IFF_6LO is supported */
+	if (ioctl(fd, TUNGETFEATURES, &flags) < 0 || !(flags & IFF_6LO)) {
+		close(fd);
+		return NULL;
+	}
+
+	return bt_6lo_new(fd);
+}
+
+struct bt_6lo *bt_6lo_new(int fd)
+{
+	struct bt_6lo *lo;
+
+	lo = new0(struct bt_6lo, 1);
+	lo->fd = fd;
+	lo->ifs = queue_new();
+
+	return bt_6lo_ref(lo);
+}
+
+struct bt_6lo *bt_6lo_ref(struct bt_6lo *lo)
+{
+	if (!lo)
+		return NULL;
+
+	__sync_fetch_and_add(&lo->ref_count, 1);
+
+	return lo;
+}
+
+void bt_6lo_unref(struct bt_6lo *lo)
+{
+	if (!lo)
+		return;
+
+	if (__sync_sub_and_fetch(&lo->ref_count, 1))
+		return;
+
+	lo_free(lo);
+}
+
+bool bt_6lo_set_debug(struct bt_6lo *lo, bt_6lo_debug_func_t callback,
+			void *user_data, bt_6lo_destroy_func_t destroy)
+{
+	if (!lo)
+		return false;
+
+	if (lo->debug_destroy)
+		lo->debug_destroy(lo->debug_data);
+
+	lo->debug_callback = callback;
+	lo->debug_destroy = destroy;
+	lo->debug_data = user_data;
+
+	return true;
+}
+
+static inline void memswap(void *dst, const void *src, size_t len)
+{
+	src += len - 1;
+
+	for (; len > 0; len--)
+		*((uint8_t *)dst++) = *((uint8_t *)src--);
+}
+
+static int if_setup(struct bt_6lo_if *iface)
+{
+	struct ifreq ifr = {};
+	int err = 0;
+	unsigned int family = ARPHRD_6LOWPAN;
+
+
+	/* Set ARPHRD_6LOWPAN as link type */
+	if (ioctl(iface->lo->fd, TUNSETLINK, family) < 0)
+		return -errno;
+
+	strcpy(ifr.ifr_name, iface->name);
+	ifr.ifr_hwaddr.sa_family = family;
+	memcpy(&ifr.ifr_hwaddr.sa_data, &iface->addr, sizeof(iface->addr));
+
+	if (ioctl(iface->lo->fd, SIOCSIFHWADDR, &ifr) < 0)
+		err = -errno;
+
+	return err;
+}
+
+static bool find_chan(const void *data, const void *match_data)
+{
+	const struct bt_6lo_chan *chan = data;
+	const struct ether_header *mac = match_data;
+
+	return !memcmp(&chan->addr, mac->ether_dhost, sizeof(chan->addr));
+}
+
+static bool if_read(struct io *io, void *user_data)
+{
+	struct bt_6lo_if *iface = user_data;
+	struct ether_header mac = {};
+	struct bt_6lo_chan *chan;
+	struct iovec iov[2];
+	ssize_t ret;
+
+	iov[0].iov_base = &mac;
+	iov[0].iov_len = sizeof(mac);
+
+	iov[1].iov_base = iface->buf;
+	iov[1].iov_len = sizeof(iface->buf);
+
+	ret = io_recv(io, iov, 2);
+	if (ret < 0 || (size_t) ret < sizeof(mac)) {
+		util_debug(iface->lo->debug_callback, iface->lo->debug_data,
+						"iface recv %zd", ret);
+		return true;
+	}
+
+	if (queue_length(iface->channels) == 1) {
+		chan = queue_peek_head(iface->channels);
+		goto done;
+	}
+
+	chan = queue_find(iface->channels, find_chan, &mac);
+	if (!chan) {
+		/* MAC doesn't match any of the existing channels? */
+		return true;
+	}
+
+done:
+	/* Update received length */
+	iov[1].iov_len = ret - sizeof(mac);
+
+	ret = io_send(chan->io, &iov[1], 1);
+	if (ret < 0) {
+		util_debug(iface->lo->debug_callback, iface->lo->debug_data,
+						"chan send %zd", ret);
+		return true;
+	}
+
+	return true;
+}
+
+static bool if_hup(struct io *io, void *user_data)
+{
+	struct bt_6lo_if *iface = user_data;
+
+	util_debug(iface->lo->debug_callback, iface->lo->debug_data,
+			"iface %s disconnected", iface->name);
+
+	queue_remove(iface->lo->ifs, iface);
+	if_free(iface);
+
+	return false;
+}
+
+int bt_6lo_add(struct bt_6lo *lo, const char *name, const uint8_t *addr)
+{
+	struct bt_6lo_if *iface;
+	struct ifreq ifr = {};
+	int err;
+
+	if (!lo)
+		return -EINVAL;
+
+	ifr.ifr_flags = IFF_6LO_FLAGS;
+	strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
+
+	if (lo->fd == -1) {
+		lo->fd = open(DEV_6LO, O_RDWR);
+		if (lo->fd < 0)
+			return -errno;
+	}
+
+	if (ioctl(lo->fd, TUNSETIFF, &ifr) < 0)
+		return -errno;
+
+	iface = new0(struct bt_6lo_if, 1);
+	iface->lo = lo;
+	memswap(&iface->addr, addr, sizeof(iface->addr));
+	strcpy(iface->name, ifr.ifr_name);
+	iface->index = if_nametoindex(iface->name);
+	iface->channels = queue_new();
+
+	err = if_setup(iface);
+	if (err < 0) {
+		if_free(iface);
+		return err;
+	}
+
+	iface->io = io_new(lo->fd);
+	io_set_close_on_destroy(iface->io, true);
+	io_set_read_handler(iface->io, if_read, iface, NULL);
+	io_set_disconnect_handler(iface->io, if_hup, iface, NULL);
+
+	util_debug(iface->lo->debug_callback, iface->lo->debug_data,
+					"iface %s added", iface->name);
+
+	lo->fd = -1;
+
+	queue_push_tail(lo->ifs, iface);
+
+	return 0;
+}
+
+static bool find_if_by_name(const void *data, const void *match_data)
+{
+	const struct bt_6lo_if *iface = data;
+	const char *name = match_data;
+
+	return !strcmp(iface->name, name);
+}
+
+static int if_name(struct bt_6lo *lo, const char *name, struct ifreq *ifr)
+{
+	struct bt_6lo_if *iface;
+
+	iface = queue_find(lo->ifs, find_if_by_name, name);
+	if (!iface)
+		return -ENOENT;
+
+	if_indextoname(iface->index, ifr->ifr_name);
+
+	return 0;
+}
+
+static int if_up(struct bt_6lo *lo, const char *name)
+{
+	struct ifreq ifr = {};
+	int fd, err;
+
+	if (!lo || !name)
+		return -EINVAL;
+
+	err = if_name(lo, name, &ifr);
+	if (err < 0)
+		return err;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+		err = -errno;
+		goto done;
+	}
+
+	ifr.ifr_flags |= IFF_UP;
+	ifr.ifr_flags |= IFF_MULTICAST;
+
+	if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+		err = -errno;
+		goto done;
+	}
+
+	util_debug(lo->debug_callback, lo->debug_data, "iface %s up",
+							ifr.ifr_name);
+
+done:
+	close(fd);
+
+	return err;
+}
+
+static int if_down(struct bt_6lo *lo, const char *name)
+{
+	struct ifreq ifr = {};
+	int fd, err;
+
+	if (!lo || !name)
+		return -EINVAL;
+
+	err = if_name(lo, name, &ifr);
+	if (err < 0)
+		return err;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+		err = -errno;
+		goto done;
+	}
+
+	ifr.ifr_flags &= ~IFF_UP;
+
+	if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+		err = -errno;
+		goto done;
+	}
+
+	util_debug(lo->debug_callback, lo->debug_data, "iface %s down",
+							ifr.ifr_name);
+
+done:
+	close(fd);
+
+	return err;
+}
+
+static bool find_if_by_addr(const void *data, const void *match_data)
+{
+	const struct bt_6lo_if *iface = data;
+	const uint8_t *addr = match_data;
+	struct ether_addr ifaddr;
+
+	memswap(&ifaddr, addr, sizeof(ifaddr));
+
+	return !memcmp(&iface->addr, &ifaddr, sizeof(iface->addr));
+}
+
+int bt_6lo_remove(struct bt_6lo *lo, const uint8_t *addr)
+{
+	struct bt_6lo_if *iface;
+
+	if (!lo)
+		return -EINVAL;
+
+	iface = queue_remove_if(lo->ifs, find_if_by_addr, (void *) addr);
+	if (!iface)
+		return -ENOENT;
+
+	util_debug(iface->lo->debug_callback, iface->lo->debug_data,
+			"iface %s removed", iface->name);
+
+	if_free(iface);
+
+	return 0;
+}
+
+static bool chan_hup(struct io *io, void *user_data)
+{
+	struct bt_6lo_chan *chan = user_data;
+	struct bt_6lo_if *iface = chan->iface;
+
+	util_debug(iface->lo->debug_callback, iface->lo->debug_data,
+						"chan %p hup", chan);
+
+	queue_remove(iface->channels, chan);
+	chan_free(chan);
+
+	/* Auto down when last IO is detached */
+	if (queue_isempty(iface->channels))
+		if_down(iface->lo, iface->name);
+
+	return false;
+}
+
+static bool chan_read(struct io *io, void *user_data)
+{
+	struct bt_6lo_chan *chan = user_data;
+	struct bt_6lo_if *iface = chan->iface;
+	struct ether_header mac = {};
+	struct iovec iov[2];
+	ssize_t ret;
+
+	iov[1].iov_base = iface->buf;
+	iov[1].iov_len = sizeof(iface->buf);
+
+	ret = io_recv(io, &iov[1], 1);
+	if (ret < 0) {
+		util_debug(iface->lo->debug_callback, iface->lo->debug_data,
+						"chan recv %zd", ret);
+		return true;
+	}
+
+	memcpy(&mac.ether_shost, &chan->addr, sizeof(mac.ether_shost));
+	memcpy(&mac.ether_dhost, &iface->addr, sizeof(mac.ether_dhost));
+
+	iov[0].iov_base = &mac;
+	iov[0].iov_len = sizeof(mac);
+
+	iov[1].iov_len = ret;
+
+	ret = io_send(iface->io, iov, 2);
+	if (ret < 0) {
+		util_debug(iface->lo->debug_callback, iface->lo->debug_data,
+						"iface send %zd", ret);
+		return true;
+	}
+
+	return true;
+}
+
+int bt_6lo_attach(struct bt_6lo *lo, const uint8_t *ifaddr, int fd,
+						const uint8_t *addr)
+{
+	struct bt_6lo_if *iface;
+	struct bt_6lo_chan *chan;
+
+	iface = queue_find(lo->ifs, find_if_by_addr, ifaddr);
+	if (!iface)
+		return -ENOENT;
+
+	chan = new0(struct bt_6lo_chan, 1);
+	chan->iface = iface;
+	memswap(&chan->addr, addr, sizeof(chan->addr));
+	chan->io = io_new(fd);
+	io_set_close_on_destroy(chan->io, true);
+	io_set_read_handler(chan->io, chan_read, chan, NULL);
+	io_set_disconnect_handler(chan->io, chan_hup, chan, NULL);
+
+	/* Auto up when first IO is attached */
+	if (queue_isempty(iface->channels))
+		if_up(lo, iface->name);
+
+	queue_push_tail(iface->channels, chan);
+
+	util_debug(iface->lo->debug_callback, iface->lo->debug_data,
+				"chan %p attached to %s", chan, iface->name);
+
+	return 0;
+}
diff --git a/src/shared/6lo.h b/src/shared/6lo.h
new file mode 100644
index 000000000..4dbe780b2
--- /dev/null
+++ b/src/shared/6lo.h
@@ -0,0 +1,40 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2017  Intel Corporation.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+struct bt_6lo;
+
+struct bt_6lo *bt_6lo_new_default(void);
+struct bt_6lo *bt_6lo_new(int fd);
+
+struct bt_6lo *bt_6lo_ref(struct bt_6lo *lo);
+void bt_6lo_unref(struct bt_6lo *lo);
+
+typedef void (*bt_6lo_destroy_func_t)(void *user_data);
+typedef void (*bt_6lo_debug_func_t)(const char *str, void *user_data);
+bool bt_6lo_set_debug(struct bt_6lo *lo, bt_6lo_debug_func_t callback,
+			void *user_data, bt_6lo_destroy_func_t destroy);
+
+int bt_6lo_add(struct bt_6lo *lo, const char *name, const uint8_t *addr);
+int bt_6lo_remove(struct bt_6lo *lo, const uint8_t *addr);
+
+int bt_6lo_attach(struct bt_6lo *lo, const uint8_t *src, int fd,
+						const uint8_t *dst);
-- 
2.13.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 3/7] unit: Add initial test for bt_6lo
  2017-10-24 13:24 [PATCH BlueZ 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
  2017-10-24 13:24 ` [PATCH BlueZ 2/7] shared: Add initial code for 6LoWPAN Luiz Augusto von Dentz
@ 2017-10-24 13:24 ` Luiz Augusto von Dentz
  2017-10-24 13:24 ` [PATCH BlueZ 4/7] uuid: Add IPSP UUID Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-24 13:24 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 Makefile.am     |   6 ++
 unit/test-6lo.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 277 insertions(+)
 create mode 100644 unit/test-6lo.c

diff --git a/Makefile.am b/Makefile.am
index bb5a77408..3ba1a8dab 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -430,6 +430,12 @@ unit_test_midi_LDADD = src/libshared-glib.la \
 			@GLIB_LIBS@ @ALSA_LIBS@
 endif
 
+unit_tests += unit/test-6lo
+
+unit_test_6lo_SOURCES = unit/test-6lo.c
+unit_test_6lo_LDADD = src/libshared-glib.la \
+				lib/libbluetooth-internal.la @GLIB_LIBS@
+
 if MAINTAINER_MODE
 noinst_PROGRAMS += $(unit_tests)
 endif
diff --git a/unit/test-6lo.c b/unit/test-6lo.c
new file mode 100644
index 000000000..77f24e795
--- /dev/null
+++ b/unit/test-6lo.c
@@ -0,0 +1,271 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2017  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 <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "src/shared/6lo.h"
+#include "src/shared/util.h"
+
+#include "src/shared/tester.h"
+
+struct test_pdu {
+	bool valid;
+	const uint8_t *data;
+	size_t size;
+};
+
+struct test_data {
+	char *test_name;
+	struct test_pdu *pdu_list;
+};
+
+struct context {
+	struct bt_6lo *lo;
+	guint source;
+	guint process;
+	int fd;
+	unsigned int pdu_offset;
+	const struct test_data *data;
+};
+
+#define data(args...) ((const unsigned char[]) { args })
+
+#define raw_pdu(args...)					\
+	{							\
+		.valid = true,					\
+		.data = data(args),				\
+		.size = sizeof(data(args)),			\
+	}
+
+#define define_test(name, function, args...)				\
+	do {								\
+		const struct test_pdu pdus[] = {			\
+			args, { }					\
+		};							\
+		static struct test_data data;				\
+		data.test_name = g_strdup(name);			\
+		data.pdu_list = g_memdup(pdus, sizeof(pdus));		\
+		tester_add(name, &data, NULL, function, NULL);		\
+	} while (0)
+
+static const uint8_t src[] = { 0xac, 0x9f, 0xa0, 0xf3, 0x42, 0x42 };
+static const uint8_t dst[] = { 0xac, 0x9f, 0xa0, 0xf3, 0x42, 0x43 };
+
+static void test_debug(const char *str, void *user_data)
+{
+	const char *prefix = user_data;
+
+	tester_debug("%s%s\n", prefix, str);
+}
+
+static void test_free(gconstpointer user_data)
+{
+	const struct test_data *data = user_data;
+
+	g_free(data->test_name);
+	g_free(data->pdu_list);
+}
+
+static void destroy_context(struct context *context)
+{
+	if (context->source > 0)
+		g_source_remove(context->source);
+
+	bt_6lo_unref(context->lo);
+
+	test_free(context->data);
+	g_free(context);
+}
+
+static gboolean context_quit(gpointer user_data)
+{
+	struct context *context = user_data;
+
+	if (context == NULL)
+		return FALSE;
+
+	if (context->process > 0)
+		g_source_remove(context->process);
+
+	destroy_context(context);
+	tester_test_passed();
+
+	return FALSE;
+}
+
+static gboolean send_pdu(gpointer user_data)
+{
+	struct context *context = user_data;
+	const struct test_pdu *pdu;
+	ssize_t len;
+
+	pdu = &context->data->pdu_list[context->pdu_offset++];
+
+	len = write(context->fd, pdu->data, pdu->size);
+
+	util_hexdump('<', pdu->data, len, test_debug, "6lo: ");
+
+	g_assert_cmpint(len, ==, pdu->size);
+
+	context->process = 0;
+	return FALSE;
+}
+
+static void context_process(struct context *context)
+{
+	if (!context->data->pdu_list[context->pdu_offset].valid) {
+		context_quit(context);
+		return;
+	}
+
+	context->process = g_idle_add(send_pdu, context);
+}
+
+static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
+							gpointer user_data)
+{
+	struct context *context = user_data;
+	const struct test_pdu *pdu;
+	unsigned char buf[1280];
+	ssize_t len;
+	int fd;
+
+	pdu = &context->data->pdu_list[context->pdu_offset++];
+
+	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+		context->source = 0;
+		g_print("%s: cond %x\n", __func__, cond);
+		return FALSE;
+	}
+
+	fd = g_io_channel_unix_get_fd(channel);
+
+	len = read(fd, buf, sizeof(buf));
+
+	g_assert(len > 0);
+
+	util_hexdump('>', buf, len, test_debug, "6lo: ");
+
+	g_assert_cmpint(len, ==, pdu->size);
+
+	g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
+
+	context_process(context);
+
+	return TRUE;
+}
+
+static struct context *create_context(gconstpointer data)
+{
+	struct bt_6lo *lo;
+	struct context *context;
+	int err = 0;
+
+	lo = bt_6lo_new_default();
+	if (!lo) {
+		err = -ENOTSUP;
+		goto fail;
+	}
+
+	err = bt_6lo_add(lo, "bt0", src);
+	if (err < 0) {
+		bt_6lo_unref(lo);
+		goto fail;
+	}
+
+	context = g_new0(struct context, 1);
+	context->lo = lo;
+
+	context->data = data;
+
+	return context;
+
+fail:
+	tester_warn("Failed to setup bt_6lo: %s", strerror(-err));
+	return NULL;
+}
+
+static void attach_client(struct context *context)
+{
+	GIOChannel *channel;
+	int err, sv[2];
+
+	err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+	g_assert(err == 0);
+
+	err = bt_6lo_attach(context->lo, src, sv[0], dst);
+	g_assert(err == 0);
+
+	channel = g_io_channel_unix_new(sv[1]);
+
+	g_io_channel_set_close_on_unref(channel, TRUE);
+	g_io_channel_set_encoding(channel, NULL, NULL);
+	g_io_channel_set_buffered(channel, FALSE);
+
+	context->source = g_io_add_watch(channel,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				test_handler, context);
+	g_assert(context->source > 0);
+
+	g_io_channel_unref(channel);
+
+	context->fd = sv[1];
+}
+
+static void test_run(gconstpointer data)
+{
+	struct context *context = create_context(data);
+
+	if (!context) {
+		tester_test_abort();
+		return;
+	}
+
+	if (!g_str_equal(context->data->test_name, "/6lo/init"))
+		attach_client(context);
+
+	context_quit(context);
+}
+
+int main(int argc, char *argv[])
+{
+	tester_init(&argc, &argv);
+
+	define_test("/6lo/init", test_run, raw_pdu());
+	define_test("/6lo/attach", test_run, raw_pdu());
+
+	return tester_run();
+}
-- 
2.13.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 4/7] uuid: Add IPSP UUID
  2017-10-24 13:24 [PATCH BlueZ 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
  2017-10-24 13:24 ` [PATCH BlueZ 2/7] shared: Add initial code for 6LoWPAN Luiz Augusto von Dentz
  2017-10-24 13:24 ` [PATCH BlueZ 3/7] unit: Add initial test for bt_6lo Luiz Augusto von Dentz
@ 2017-10-24 13:24 ` Luiz Augusto von Dentz
  2017-10-24 13:24 ` [PATCH BlueZ 5/7] build: Add IPSP plugin Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-24 13:24 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds IPSP UUID in string format.
---
 lib/uuid.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 2c57a3378..71ed3df3b 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -81,6 +81,8 @@ extern "C" {
 #define SENSOR_LOCATION_UUID	"00002a5d-0000-1000-8000-00805f9b34fb"
 #define SC_CONTROL_POINT_UUID	"00002a55-0000-1000-8000-00805f9b34fb"
 
+#define IPSP_UUID		"00001820-0000-1000-8000-00805f9b34fb"
+
 #define RFCOMM_UUID_STR		"00000003-0000-1000-8000-00805f9b34fb"
 
 #define HDP_UUID		"00001400-0000-1000-8000-00805f9b34fb"
-- 
2.13.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 5/7] build: Add IPSP plugin
  2017-10-24 13:24 [PATCH BlueZ 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2017-10-24 13:24 ` [PATCH BlueZ 4/7] uuid: Add IPSP UUID Luiz Augusto von Dentz
@ 2017-10-24 13:24 ` Luiz Augusto von Dentz
  2017-10-24 13:24 ` [PATCH BlueZ 6/7] ipsp: Connect to IPSP PSM Luiz Augusto von Dentz
  2017-10-24 13:24 ` [PATCH BlueZ 7/7] ipsp: Add support for bt_6lo Luiz Augusto von Dentz
  5 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-24 13:24 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds the initial plugin structure to handle IPSP profile.
---
 Makefile.plugins        |   5 ++
 configure.ac            |   4 ++
 profiles/network/ipsp.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 141 insertions(+)
 create mode 100644 profiles/network/ipsp.c

diff --git a/Makefile.plugins b/Makefile.plugins
index 73377e532..b5127b697 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -53,6 +53,11 @@ builtin_sources += profiles/network/manager.c \
 			profiles/network/connection.c
 endif
 
+if IPSP
+builtin_modules += ipsp
+builtin_sources += profiles/network/ipsp.c
+endif
+
 if HID
 builtin_modules += input
 builtin_sources += profiles/input/manager.c \
diff --git a/configure.ac b/configure.ac
index 964101412..24489f7d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -160,6 +160,10 @@ AC_ARG_ENABLE(network, AC_HELP_STRING([--disable-network],
 		[disable network profiles]), [enable_network=${enableval}])
 AM_CONDITIONAL(NETWORK, test "${enable_network}" != "no")
 
+AC_ARG_ENABLE(ipsp, AC_HELP_STRING([--disable-ipsp],
+		[disable ipsp profile]), [enable_ipsp=${enableval}])
+AM_CONDITIONAL(IPSP, test "${enable_ipsp}" != "no")
+
 AC_ARG_ENABLE(hid, AC_HELP_STRING([--disable-hid],
 		[disable HID profile]), [enable_hid=${enableval}])
 AM_CONDITIONAL(HID, test "${enable_hid}" != "no")
diff --git a/profiles/network/ipsp.c b/profiles/network/ipsp.c
new file mode 100644
index 000000000..2645b0598
--- /dev/null
+++ b/profiles/network/ipsp.c
@@ -0,0 +1,132 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2017 Intel Corporation
+ *
+ *  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 <stdbool.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
+#include "src/shared/util.h"
+#include "src/shared/att.h"
+#include "src/shared/queue.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/profile.h"
+#include "src/service.h"
+#include "src/log.h"
+
+#define IPSP_UUID16 0x1820
+
+static int ipsp_probe(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	const char *path = device_get_path(device);
+
+	DBG("path %s", path);
+
+	return 0;
+}
+
+static void ipsp_remove(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	const char *path = device_get_path(device);
+
+	DBG("path %s", path);
+}
+
+static void foreach_ipsp_service(struct gatt_db_attribute *attr,
+						void *user_data)
+{
+	bool *found = user_data;
+
+	*found = true;
+}
+
+static int ipsp_accept(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct gatt_db *db = btd_device_get_gatt_db(device);
+	const char *path = device_get_path(device);
+	bool found = false;
+	bt_uuid_t ipsp_uuid;
+
+	DBG("path %s", path);
+
+	/* Handle the IPSP services */
+	bt_uuid16_create(&ipsp_uuid, IPSP_UUID16);
+	gatt_db_foreach_service(db, &ipsp_uuid, foreach_ipsp_service, &found);
+	if (!found) {
+		error("IPSP attribute not found");
+		return -EINVAL;
+	}
+
+	btd_service_connecting_complete(service, 0);
+
+	return 0;
+}
+
+static int ipsp_disconnect(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	const char *path = device_get_path(device);
+
+	DBG("path %s", path);
+
+	btd_service_disconnecting_complete(service, 0);
+
+	return 0;
+}
+
+static struct btd_profile ipsp_profile = {
+	.name		= "network-ipsp",
+	.remote_uuid	= IPSP_UUID,
+	.device_probe	= ipsp_probe,
+	.device_remove	= ipsp_remove,
+	.accept		= ipsp_accept,
+	.disconnect	= ipsp_disconnect,
+};
+
+static int ipsp_init(void)
+{
+	return btd_profile_register(&ipsp_profile);
+}
+
+static void ipsp_exit(void)
+{
+	btd_profile_unregister(&ipsp_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(ipsp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+			ipsp_init, ipsp_exit)
-- 
2.13.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 6/7] ipsp: Connect to IPSP PSM
  2017-10-24 13:24 [PATCH BlueZ 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2017-10-24 13:24 ` [PATCH BlueZ 5/7] build: Add IPSP plugin Luiz Augusto von Dentz
@ 2017-10-24 13:24 ` Luiz Augusto von Dentz
  2017-10-24 13:24 ` [PATCH BlueZ 7/7] ipsp: Add support for bt_6lo Luiz Augusto von Dentz
  5 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-24 13:24 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

In case the remote device has IPSP service connect attempt to the IPSP
L2CAP PSM.
---
 profiles/network/ipsp.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 98 insertions(+), 3 deletions(-)

diff --git a/profiles/network/ipsp.c b/profiles/network/ipsp.c
index 2645b0598..28683f4b6 100644
--- a/profiles/network/ipsp.c
+++ b/profiles/network/ipsp.c
@@ -34,6 +34,7 @@
 #include "lib/sdp.h"
 #include "lib/uuid.h"
 
+#include "btio/btio.h"
 #include "src/shared/util.h"
 #include "src/shared/att.h"
 #include "src/shared/queue.h"
@@ -47,6 +48,28 @@
 #include "src/log.h"
 
 #define IPSP_UUID16 0x1820
+#define IPSP_PSM 0x0023
+#define IPSP_MTU 1280
+
+struct ipsp_session {
+	GIOChannel *io;
+	unsigned int id;
+};
+
+static void ipsp_cleanup(struct btd_service *service)
+{
+	struct ipsp_session *session = btd_service_get_user_data(service);
+
+	if (!session)
+		return;
+
+	btd_service_set_user_data(service, NULL);
+
+	if (session->id > 0)
+		g_source_remove(session->id);
+
+	g_io_channel_unref(session->io);
+}
 
 static int ipsp_probe(struct btd_service *service)
 {
@@ -64,6 +87,49 @@ static void ipsp_remove(struct btd_service *service)
 	const char *path = device_get_path(device);
 
 	DBG("path %s", path);
+
+	ipsp_cleanup(service);
+}
+
+static gboolean ipsp_session(GIOChannel *chan, GIOCondition cond,
+				gpointer data)
+{
+	struct btd_service *service = data;
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	if (cond & (G_IO_HUP | G_IO_ERR)) {
+		DBG("IPSP session disconnected");
+		ipsp_cleanup(service);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void ipsp_connect(GIOChannel *io, GError *err, gpointer user_data)
+{
+	struct btd_service *service = user_data;
+	struct ipsp_session *session = btd_service_get_user_data(service);
+
+	if (err) {
+		DBG("%s", err->message);
+
+		ipsp_cleanup(service);
+
+		btd_service_connecting_complete(service, -EIO);
+		return;
+	}
+
+	session->id = g_io_add_watch(io,
+				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+				(GIOFunc) ipsp_session, service);
+
+	g_io_channel_unref(session->io);
+	session->io = NULL;
+
+	btd_service_connecting_complete(service, 0);
 }
 
 static void foreach_ipsp_service(struct gatt_db_attribute *attr,
@@ -77,12 +143,13 @@ static void foreach_ipsp_service(struct gatt_db_attribute *attr,
 static int ipsp_accept(struct btd_service *service)
 {
 	struct btd_device *device = btd_service_get_device(service);
+	struct btd_adapter *adapter = device_get_adapter(device);
 	struct gatt_db *db = btd_device_get_gatt_db(device);
-	const char *path = device_get_path(device);
 	bool found = false;
 	bt_uuid_t ipsp_uuid;
+	struct ipsp_session *session;
 
-	DBG("path %s", path);
+	DBG("path %s", device_get_path(device));
 
 	/* Handle the IPSP services */
 	bt_uuid16_create(&ipsp_uuid, IPSP_UUID16);
@@ -92,7 +159,33 @@ static int ipsp_accept(struct btd_service *service)
 		return -EINVAL;
 	}
 
-	btd_service_connecting_complete(service, 0);
+	session = g_new0(struct ipsp_session, 1);
+	if (!session) {
+		error("Unable to allocate IPSP session");
+		return -ENOMEM;
+	}
+
+	/* Connect L2CAP channel */
+	session->io = bt_io_connect(ipsp_connect, service, NULL, NULL,
+				BT_IO_OPT_SOURCE_BDADDR,
+				btd_adapter_get_address(adapter),
+				BT_IO_OPT_SOURCE_TYPE,
+				btd_adapter_get_address_type(adapter),
+				BT_IO_OPT_DEST_BDADDR,
+				device_get_address(device),
+				BT_IO_OPT_DEST_TYPE,
+				btd_device_get_bdaddr_type(device),
+				BT_IO_OPT_PSM, IPSP_PSM,
+				BT_IO_OPT_IMTU, IPSP_MTU,
+				BT_IO_OPT_INVALID);
+	if (!session->io) {
+		error("Unable create IPSP connection");
+		g_free(session);
+		return -EIO;
+	}
+
+	/* Attach session to the service */
+	btd_service_set_user_data(service, session);
 
 	return 0;
 }
@@ -104,6 +197,8 @@ static int ipsp_disconnect(struct btd_service *service)
 
 	DBG("path %s", path);
 
+	ipsp_cleanup(service);
+
 	btd_service_disconnecting_complete(service, 0);
 
 	return 0;
-- 
2.13.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH BlueZ 7/7] ipsp: Add support for bt_6lo
  2017-10-24 13:24 [PATCH BlueZ 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
                   ` (4 preceding siblings ...)
  2017-10-24 13:24 ` [PATCH BlueZ 6/7] ipsp: Connect to IPSP PSM Luiz Augusto von Dentz
@ 2017-10-24 13:24 ` Luiz Augusto von Dentz
  5 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-24 13:24 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This makes use of bt_6lo instance to create interfaces and attach
channels to them.
---
 profiles/network/ipsp.c | 131 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 111 insertions(+), 20 deletions(-)

diff --git a/profiles/network/ipsp.c b/profiles/network/ipsp.c
index 28683f4b6..f6bace956 100644
--- a/profiles/network/ipsp.c
+++ b/profiles/network/ipsp.c
@@ -40,6 +40,7 @@
 #include "src/shared/queue.h"
 #include "src/shared/gatt-db.h"
 #include "src/shared/gatt-client.h"
+#include "src/shared/6lo.h"
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/device.h"
@@ -50,8 +51,12 @@
 #define IPSP_UUID16 0x1820
 #define IPSP_PSM 0x0023
 #define IPSP_MTU 1280
+#define IF_PREFIX "bt"
+
+static struct bt_6lo *lo;
 
 struct ipsp_session {
+	int ifindex;
 	GIOChannel *io;
 	unsigned int id;
 };
@@ -63,36 +68,49 @@ static void ipsp_cleanup(struct btd_service *service)
 	if (!session)
 		return;
 
-	btd_service_set_user_data(service, NULL);
-
-	if (session->id > 0)
+	if (session->id > 0) {
 		g_source_remove(session->id);
+		session->id = 0;
+	}
 
-	g_io_channel_unref(session->io);
+	if (session->io) {
+		g_io_channel_unref(session->io);
+		session->io = NULL;
+	}
 }
 
 static int ipsp_probe(struct btd_service *service)
 {
 	struct btd_device *device = btd_service_get_device(service);
 	const char *path = device_get_path(device);
+	struct ipsp_session *session;
 
 	DBG("path %s", path);
 
+	session = new0(struct ipsp_session, 1);
+
+	/* Attach session to the service */
+	btd_service_set_user_data(service, session);
+
 	return 0;
 }
 
 static void ipsp_remove(struct btd_service *service)
 {
 	struct btd_device *device = btd_service_get_device(service);
+	struct ipsp_session *session = btd_service_get_user_data(service);
 	const char *path = device_get_path(device);
 
 	DBG("path %s", path);
 
 	ipsp_cleanup(service);
+
+	btd_service_set_user_data(service, NULL);
+
+	g_free(session);
 }
 
-static gboolean ipsp_session(GIOChannel *chan, GIOCondition cond,
-				gpointer data)
+static gboolean ipsp_hup(GIOChannel *chan, GIOCondition cond, gpointer data)
 {
 	struct btd_service *service = data;
 
@@ -112,19 +130,38 @@ static void ipsp_connect(GIOChannel *io, GError *err, gpointer user_data)
 {
 	struct btd_service *service = user_data;
 	struct ipsp_session *session = btd_service_get_user_data(service);
+	GError *gerr = NULL;
+	bdaddr_t src, dst;
+	int fd;
 
 	if (err) {
 		DBG("%s", err->message);
-
 		ipsp_cleanup(service);
+		btd_service_connecting_complete(service, -EIO);
+		return;
+	}
+
+	bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src,
+					BT_IO_OPT_DEST_BDADDR, &dst,
+					BT_IO_OPT_INVALID);
+	if (gerr) {
+		error("bt_io_get: %s", gerr->message);
+		g_error_free(gerr);
+		g_io_channel_unref(io);
+		return;
+	}
+
+	fd = g_io_channel_unix_get_fd(io);
 
+	if (bt_6lo_attach(lo, src.b, fd, dst.b) < 0) {
+		DBG("Unable to attach channel");
+		ipsp_cleanup(service);
 		btd_service_connecting_complete(service, -EIO);
 		return;
 	}
 
-	session->id = g_io_add_watch(io,
-				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-				(GIOFunc) ipsp_session, service);
+	session->id = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+					(GIOFunc) ipsp_hup, service);
 
 	g_io_channel_unref(session->io);
 	session->io = NULL;
@@ -144,10 +181,10 @@ static int ipsp_accept(struct btd_service *service)
 {
 	struct btd_device *device = btd_service_get_device(service);
 	struct btd_adapter *adapter = device_get_adapter(device);
+	struct ipsp_session *session = btd_service_get_user_data(service);
 	struct gatt_db *db = btd_device_get_gatt_db(device);
 	bool found = false;
 	bt_uuid_t ipsp_uuid;
-	struct ipsp_session *session;
 
 	DBG("path %s", device_get_path(device));
 
@@ -159,11 +196,8 @@ static int ipsp_accept(struct btd_service *service)
 		return -EINVAL;
 	}
 
-	session = g_new0(struct ipsp_session, 1);
-	if (!session) {
-		error("Unable to allocate IPSP session");
-		return -ENOMEM;
-	}
+	if (session->io)
+		return -EINPROGRESS;
 
 	/* Connect L2CAP channel */
 	session->io = bt_io_connect(ipsp_connect, service, NULL, NULL,
@@ -184,9 +218,6 @@ static int ipsp_accept(struct btd_service *service)
 		return -EIO;
 	}
 
-	/* Attach session to the service */
-	btd_service_set_user_data(service, session);
-
 	return 0;
 }
 
@@ -213,14 +244,74 @@ static struct btd_profile ipsp_profile = {
 	.disconnect	= ipsp_disconnect,
 };
 
+static int net_6lo_probe(struct btd_adapter *adapter)
+{
+	uint16_t index = btd_adapter_get_index(adapter);
+	const bdaddr_t *addr = btd_adapter_get_address(adapter);
+	char *ifname;
+	int err;
+
+	DBG("");
+
+	ifname = g_strdup_printf("%s%u", IF_PREFIX, index);
+
+	err = bt_6lo_add(lo, ifname, addr->b);
+
+	g_free(ifname);
+
+	return err;
+}
+
+static void net_6lo_remove(struct btd_adapter *adapter)
+{
+	const bdaddr_t *addr = btd_adapter_get_address(adapter);
+
+	DBG("");
+
+	bt_6lo_remove(lo, addr->b);
+}
+
+static struct btd_adapter_driver net_6lo_driver = {
+	.name	= "network-6lo",
+	.probe	= net_6lo_probe,
+	.remove	= net_6lo_remove,
+};
+
+static void net_6lo_debug(const char *str, void *user_data)
+{
+	DBG("%s", str);
+}
+
 static int ipsp_init(void)
 {
-	return btd_profile_register(&ipsp_profile);
+	int err;
+
+	lo = bt_6lo_new_default();
+	if (!lo)
+		return -ENOTSUP;
+
+	bt_6lo_set_debug(lo, net_6lo_debug, NULL, NULL);
+
+	err = btd_register_adapter_driver(&net_6lo_driver);
+	if (err < 0) {
+		bt_6lo_unref(lo);
+		return err;
+	}
+
+	err = btd_profile_register(&ipsp_profile);
+	if (err < 0) {
+		btd_unregister_adapter_driver(&net_6lo_driver);
+		bt_6lo_unref(lo);
+	}
+
+	return err;
 }
 
 static void ipsp_exit(void)
 {
 	btd_profile_unregister(&ipsp_profile);
+	btd_unregister_adapter_driver(&net_6lo_driver);
+	bt_6lo_unref(lo);
 }
 
 BLUETOOTH_PLUGIN_DEFINE(ipsp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-- 
2.13.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-10-24 13:24 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-10-24 13:24 [PATCH BlueZ 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
2017-10-24 13:24 ` [PATCH BlueZ 2/7] shared: Add initial code for 6LoWPAN Luiz Augusto von Dentz
2017-10-24 13:24 ` [PATCH BlueZ 3/7] unit: Add initial test for bt_6lo Luiz Augusto von Dentz
2017-10-24 13:24 ` [PATCH BlueZ 4/7] uuid: Add IPSP UUID Luiz Augusto von Dentz
2017-10-24 13:24 ` [PATCH BlueZ 5/7] build: Add IPSP plugin Luiz Augusto von Dentz
2017-10-24 13:24 ` [PATCH BlueZ 6/7] ipsp: Connect to IPSP PSM Luiz Augusto von Dentz
2017-10-24 13:24 ` [PATCH BlueZ 7/7] ipsp: Add support for bt_6lo Luiz Augusto von Dentz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).