From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx> 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 -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html