linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/7] 6LoWPAN userspace support
@ 2017-10-20 10:22 Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-20 10:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: patrik.flykt, linux-wpan

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

This introduces support for 6LoWPAN userspace interface creation along
with IPSP plugin which takes care of L2CAP channel creation.

The bt_6lo instance handles all the details to create the network
interface and also attach channels to it so any io is automatically
forward to the right path. The plugin make use of bt_6lo and create
interfaces for each adapter available using "bt" as prefix followed by
adapter index.

At the current stage only router/central role is supported since
peripheral role may actually need to be enabled via advertisement which
perhaps will require a D-Bus to be triggered on demand.

Since the IPSP plugins does actually register a proper profile driver
Device.Connect can now attempt to connect the IPSP channel and then
proceed to attach the channel to interface, so it is well integrated
with existing D-Bus APIs.

Note that this all depends on TUN/TAP changes proposed here:
http://www.spinics.net/lists/linux-bluetooth/msg72471.html

Luiz Augusto von Dentz (7):
  shared/io: Add io_recv
  shared: Add initial code for 6LoWPAN
  unit: Add initial test for bt_6lo
  uuid: Add IPSP UUID
  build: Add IPSP plugin
  ipsp: Connect to IPSP PSM
  ipsp: Add support for bt_6lo

 Makefile.am             |   8 +-
 Makefile.plugins        |   5 +
 configure.ac            |   4 +
 lib/uuid.h              |   2 +
 profiles/network/ipsp.c | 318 +++++++++++++++++++++++++++++++
 src/shared/6lo.c        | 493 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/6lo.h        |  40 ++++
 src/shared/io-glib.c    |  20 ++
 src/shared/io.h         |   1 +
 unit/test-6lo.c         | 271 ++++++++++++++++++++++++++
 10 files changed, 1161 insertions(+), 1 deletion(-)
 create mode 100644 profiles/network/ipsp.c
 create mode 100644 src/shared/6lo.c
 create mode 100644 src/shared/6lo.h
 create mode 100644 unit/test-6lo.c

-- 
2.13.6


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

* [RFC 1/7] shared/io: Add io_recv
  2017-10-20 10:22 [RFC 0/7] 6LoWPAN userspace support Luiz Augusto von Dentz
@ 2017-10-20 10:22 ` Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 2/7] shared: Add initial code for 6LoWPAN Luiz Augusto von Dentz
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-20 10:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: patrik.flykt, linux-wpan

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] 8+ messages in thread

* [RFC 2/7] shared: Add initial code for 6LoWPAN
  2017-10-20 10:22 [RFC 0/7] 6LoWPAN userspace support Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
@ 2017-10-20 10:22 ` Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 3/7] unit: Add initial test for bt_6lo Luiz Augusto von Dentz
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-20 10:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: patrik.flykt, linux-wpan

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 | 493 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/6lo.h |  40 +++++
 3 files changed, 534 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..70f7ec25c
--- /dev/null
+++ b/src/shared/6lo.c
@@ -0,0 +1,493 @@
+/*
+ *
+ *  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;
+
+	if ((fd = open(DEV_6LO, O_RDWR)) < 0)
+		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_set_mac(struct bt_6lo_if *iface, const uint8_t *addr)
+{
+	struct ifreq ifr = {};
+	int err = 0;
+
+	strcpy(ifr.ifr_name, iface->name);
+	/* TODO: This should be changed to ARPHRD_6LOWPAN */
+	ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+	/* MAC address is big endian */
+	memswap(&ifr.ifr_hwaddr.sa_data, addr, 6);
+
+	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;
+
+	/* read back iff flags to see if IFF_6LO is supported */
+	if (ioctl(lo->fd, TUNGETIFF, &ifr) < 0 || !(ifr.ifr_flags & IFF_6LO))
+		return -ENOTSUP;
+
+	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_set_mac(iface, addr);
+	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 err;
+
+	if (!lo || !name)
+		return -EINVAL;
+
+	err = if_name(lo, name, &ifr);
+	if (err < 0)
+		return err;
+
+	ifr.ifr_flags |= IFF_UP;
+	ifr.ifr_flags |= IFF_RUNNING;
+	ifr.ifr_flags |= IFF_MULTICAST;
+
+	if (ioctl(lo->fd, SIOCSIFFLAGS, &ifr) < 0)
+		return -errno;
+
+	util_debug(lo->debug_callback, lo->debug_data, "iface %s up",
+							ifr.ifr_name);
+
+	return err;
+}
+
+static int if_down(struct bt_6lo *lo, const char *name)
+{
+	struct ifreq ifr = {};
+	int err;
+
+	if (!lo || !name)
+		return -EINVAL;
+
+	err = if_name(lo, name, &ifr);
+	if (err < 0)
+		return err;
+
+	ifr.ifr_flags &= ~IFF_UP;
+
+	if (ioctl(lo->fd, SIOCSIFFLAGS, &ifr) < 0)
+		return -errno;
+
+	util_debug(lo->debug_callback, lo->debug_data, "iface %s down",
+							ifr.ifr_name);
+
+	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] 8+ messages in thread

* [RFC 3/7] unit: Add initial test for bt_6lo
  2017-10-20 10:22 [RFC 0/7] 6LoWPAN userspace support Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 2/7] shared: Add initial code for 6LoWPAN Luiz Augusto von Dentz
@ 2017-10-20 10:22 ` Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 4/7] uuid: Add IPSP UUID Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-20 10:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: patrik.flykt, linux-wpan

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] 8+ messages in thread

* [RFC 4/7] uuid: Add IPSP UUID
  2017-10-20 10:22 [RFC 0/7] 6LoWPAN userspace support Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2017-10-20 10:22 ` [RFC 3/7] unit: Add initial test for bt_6lo Luiz Augusto von Dentz
@ 2017-10-20 10:22 ` Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 5/7] build: Add IPSP plugin Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-20 10:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: patrik.flykt, linux-wpan

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] 8+ messages in thread

* [RFC 5/7] build: Add IPSP plugin
  2017-10-20 10:22 [RFC 0/7] 6LoWPAN userspace support Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2017-10-20 10:22 ` [RFC 4/7] uuid: Add IPSP UUID Luiz Augusto von Dentz
@ 2017-10-20 10:22 ` Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 6/7] ipsp: Connect to IPSP PSM Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 7/7] ipsp: Add support for bt_6lo Luiz Augusto von Dentz
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-20 10:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: patrik.flykt, linux-wpan

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] 8+ messages in thread

* [RFC 6/7] ipsp: Connect to IPSP PSM
  2017-10-20 10:22 [RFC 0/7] 6LoWPAN userspace support Luiz Augusto von Dentz
                   ` (4 preceding siblings ...)
  2017-10-20 10:22 ` [RFC 5/7] build: Add IPSP plugin Luiz Augusto von Dentz
@ 2017-10-20 10:22 ` Luiz Augusto von Dentz
  2017-10-20 10:22 ` [RFC 7/7] ipsp: Add support for bt_6lo Luiz Augusto von Dentz
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-20 10:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: patrik.flykt, linux-wpan

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] 8+ messages in thread

* [RFC 7/7] ipsp: Add support for bt_6lo
  2017-10-20 10:22 [RFC 0/7] 6LoWPAN userspace support Luiz Augusto von Dentz
                   ` (5 preceding siblings ...)
  2017-10-20 10:22 ` [RFC 6/7] ipsp: Connect to IPSP PSM Luiz Augusto von Dentz
@ 2017-10-20 10:22 ` Luiz Augusto von Dentz
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2017-10-20 10:22 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: patrik.flykt, linux-wpan

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] 8+ messages in thread

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

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-10-20 10:22 [RFC 0/7] 6LoWPAN userspace support Luiz Augusto von Dentz
2017-10-20 10:22 ` [RFC 1/7] shared/io: Add io_recv Luiz Augusto von Dentz
2017-10-20 10:22 ` [RFC 2/7] shared: Add initial code for 6LoWPAN Luiz Augusto von Dentz
2017-10-20 10:22 ` [RFC 3/7] unit: Add initial test for bt_6lo Luiz Augusto von Dentz
2017-10-20 10:22 ` [RFC 4/7] uuid: Add IPSP UUID Luiz Augusto von Dentz
2017-10-20 10:22 ` [RFC 5/7] build: Add IPSP plugin Luiz Augusto von Dentz
2017-10-20 10:22 ` [RFC 6/7] ipsp: Connect to IPSP PSM Luiz Augusto von Dentz
2017-10-20 10:22 ` [RFC 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).