summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRavi kumar Veeramally <ravikumar.veeramally@linux.intel.com>2013-11-29 16:20:40 +0200
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2013-11-29 17:10:19 +0200
commit6f5d2be49335675950d36a9e07d0c3f80ee09922 (patch)
tree1ed5a6bbfa09a3412f67ddb42b7dc66c5b0da57b
parent9e08218d0f52f573f9c1d12df650647d4a833d0c (diff)
downloadbluez-6f5d2be49335675950d36a9e07d0c3f80ee09922.tar.gz
profiles/network: Refactor bnep connection setup functionality
Moving bnep connection setup related functionality to common.c. Provided bnep_connect call with bnep_connect_cb for status and bnep interface name. It will be simple if someone want to utilize this call otherwise they have to reimplement similar functionality with minimal changes (e.g. android/pan).
-rw-r--r--profiles/network/common.c195
-rw-r--r--profiles/network/common.h5
-rw-r--r--profiles/network/connection.c172
-rw-r--r--profiles/network/server.c3
4 files changed, 211 insertions, 164 deletions
diff --git a/profiles/network/common.c b/profiles/network/common.c
index 0b291bdb3..71154c895 100644
--- a/profiles/network/common.c
+++ b/profiles/network/common.c
@@ -46,6 +46,9 @@
#include "common.h"
#include "lib/uuid.h"
+#define CON_SETUP_RETRIES 3
+#define CON_SETUP_TO 9
+
static int ctl;
static struct {
@@ -59,6 +62,35 @@ static struct {
{ NULL }
};
+struct __service_16 {
+ uint16_t dst;
+ uint16_t src;
+} __attribute__ ((packed));
+
+struct bnep_conn {
+ GIOChannel *io;
+ uint16_t src;
+ uint16_t dst;
+ guint attempts;
+ guint setup_to;
+ void *data;
+ bnep_connect_cb conn_cb;
+};
+
+static void free_bnep_connect(struct bnep_conn *bc)
+{
+ if (!bc)
+ return;
+
+ if (bc->io) {
+ g_io_channel_unref(bc->io);
+ bc->io = NULL;
+ }
+
+ g_free(bc);
+ bc = NULL;
+}
+
uint16_t bnep_service_id(const char *svc)
{
int i;
@@ -149,9 +181,9 @@ int bnep_connadd(int sk, uint16_t role, char *dev)
{
struct bnep_connadd_req req;
+ memset(dev, 0, 16);
memset(&req, 0, sizeof(req));
- strncpy(req.device, dev, 16);
- req.device[15] = '\0';
+ strcpy(req.device, "bnep%d");
req.sock = sk;
req.role = role;
if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
@@ -215,6 +247,165 @@ int bnep_if_down(const char *devname)
return 0;
}
+static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer data)
+{
+ struct bnep_conn *bc = data;
+ struct bnep_control_rsp *rsp;
+ struct timeval timeo;
+ char pkt[BNEP_MTU];
+ char iface[16];
+ ssize_t r;
+ int sk;
+
+ if (cond & G_IO_NVAL)
+ goto failed;
+
+ if (bc->setup_to > 0) {
+ g_source_remove(bc->setup_to);
+ bc->setup_to = 0;
+ }
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ error("Hangup or error on l2cap server socket");
+ goto failed;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+ memset(pkt, 0, BNEP_MTU);
+ r = read(sk, pkt, sizeof(pkt) - 1);
+ if (r < 0) {
+ error("IO Channel read error");
+ goto failed;
+ }
+
+ if (r == 0) {
+ error("No packet received on l2cap socket");
+ goto failed;
+ }
+
+ errno = EPROTO;
+
+ if ((size_t) r < sizeof(*rsp)) {
+ error("Packet received is not bnep type");
+ goto failed;
+ }
+
+ rsp = (void *) pkt;
+ if (rsp->type != BNEP_CONTROL) {
+ error("Packet received is not bnep type");
+ goto failed;
+ }
+
+ if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
+ return TRUE;
+
+ r = ntohs(rsp->resp);
+ if (r != BNEP_SUCCESS) {
+ error("bnep failed");
+ goto failed;
+ }
+
+ memset(&timeo, 0, sizeof(timeo));
+ timeo.tv_sec = 0;
+ setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
+
+ sk = g_io_channel_unix_get_fd(bc->io);
+ if (bnep_connadd(sk, bc->src, iface)) {
+ error("bnep conn could not be added");
+ goto failed;
+ }
+
+ if (bnep_if_up(iface)) {
+ error("could not up %s", iface);
+ goto failed;
+ }
+
+ bc->conn_cb(chan, iface, 0, bc->data);
+ free_bnep_connect(bc);
+
+ return FALSE;
+
+failed:
+ bc->conn_cb(NULL, NULL, -EIO, bc->data);
+ free_bnep_connect(bc);
+
+ return FALSE;
+}
+
+static int bnep_setup_conn_req(struct bnep_conn *bc)
+{
+ struct bnep_setup_conn_req *req;
+ struct __service_16 *s;
+ unsigned char pkt[BNEP_MTU];
+ int fd;
+
+ /* Send request */
+ req = (void *) pkt;
+ req->type = BNEP_CONTROL;
+ req->ctrl = BNEP_SETUP_CONN_REQ;
+ req->uuid_size = 2; /* 16bit UUID */
+ s = (void *) req->service;
+ s->src = htons(bc->src);
+ s->dst = htons(bc->dst);
+
+ fd = g_io_channel_unix_get_fd(bc->io);
+ if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) {
+ error("bnep connection req send failed: %s", strerror(errno));
+ return -errno;
+ }
+
+ bc->attempts++;
+
+ return 0;
+}
+
+static gboolean bnep_conn_req_to(gpointer user_data)
+{
+ struct bnep_conn *bc = user_data;
+
+ if (bc->attempts == CON_SETUP_RETRIES) {
+ error("Too many bnep connection attempts");
+ } else {
+ error("bnep connection setup TO, retrying...");
+ if (bnep_setup_conn_req(bc) == 0)
+ return TRUE;
+ }
+
+ bc->conn_cb(NULL, NULL, -ETIMEDOUT, bc->data);
+ free_bnep_connect(bc);
+
+ return FALSE;
+}
+
+int bnep_connect(int sk, uint16_t src, uint16_t dst, bnep_connect_cb conn_cb,
+ void *data)
+{
+ struct bnep_conn *bc;
+ int err;
+
+ if (!conn_cb)
+ return -EINVAL;
+
+ bc = g_new0(struct bnep_conn, 1);
+ bc->io = g_io_channel_unix_new(sk);
+ bc->attempts = 0;
+ bc->src = src;
+ bc->dst = dst;
+ bc->conn_cb = conn_cb;
+ bc->data = data;
+
+ err = bnep_setup_conn_req(bc);
+ if (err < 0)
+ return err;
+
+ bc->setup_to = g_timeout_add_seconds(CON_SETUP_TO,
+ bnep_conn_req_to, bc);
+ g_io_add_watch(bc->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ bnep_setup_cb, bc);
+ return 0;
+}
+
int bnep_add_to_bridge(const char *devname, const char *bridge)
{
int ifindex;
diff --git a/profiles/network/common.h b/profiles/network/common.h
index 9a8caac0b..9043e46f2 100644
--- a/profiles/network/common.h
+++ b/profiles/network/common.h
@@ -35,3 +35,8 @@ int bnep_if_up(const char *devname);
int bnep_if_down(const char *devname);
int bnep_add_to_bridge(const char *devname, const char *bridge);
int bnep_del_from_bridge(const char *devname, const char *bridge);
+
+typedef void (*bnep_connect_cb) (GIOChannel *chan, char *iface, int err,
+ void *data);
+int bnep_connect(int sk, uint16_t src, uint16_t dst, bnep_connect_cb conn_cb,
+ void *data);
diff --git a/profiles/network/connection.c b/profiles/network/connection.c
index 596626845..d100580c3 100644
--- a/profiles/network/connection.c
+++ b/profiles/network/connection.c
@@ -51,8 +51,6 @@
#include "connection.h"
#define NETWORK_PEER_INTERFACE "org.bluez.Network1"
-#define CON_SETUP_RETRIES 3
-#define CON_SETUP_TO 9
typedef enum {
CONNECTED,
@@ -73,16 +71,9 @@ struct network_conn {
GIOChannel *io;
guint dc_id;
struct network_peer *peer;
- guint attempt_cnt;
- guint timeout_source;
DBusMessage *connect;
};
-struct __service_16 {
- uint16_t dst;
- uint16_t src;
-} __attribute__ ((packed));
-
static GSList *peers = NULL;
static uint16_t get_service_id(struct btd_service *service)
@@ -163,11 +154,6 @@ static void local_connect_cb(struct network_conn *nc, int err)
static void cancel_connection(struct network_conn *nc, int err)
{
- if (nc->timeout_source > 0) {
- g_source_remove(nc->timeout_source);
- nc->timeout_source = 0;
- }
-
btd_service_connecting_complete(nc->service, err);
if (nc->connect)
local_connect_cb(nc, err);
@@ -200,83 +186,24 @@ static void disconnect_cb(struct btd_device *device, gboolean removal,
connection_destroy(NULL, user_data);
}
-static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
- gpointer data)
+static void bnep_conn_cb(GIOChannel *chan, char *iface, int err, void *data)
{
struct network_conn *nc = data;
- struct bnep_control_rsp *rsp;
- struct timeval timeo;
- char pkt[BNEP_MTU];
- ssize_t r;
- int sk;
const char *path;
DBusConnection *conn;
- DBG("cond %u", cond);
-
- if (cond & G_IO_NVAL)
- return FALSE;
-
- if (nc->timeout_source > 0) {
- g_source_remove(nc->timeout_source);
- nc->timeout_source = 0;
- }
-
- if (cond & (G_IO_HUP | G_IO_ERR)) {
- error("Hangup or error on l2cap server socket");
- goto failed;
- }
-
- sk = g_io_channel_unix_get_fd(chan);
-
- memset(pkt, 0, BNEP_MTU);
- r = read(sk, pkt, sizeof(pkt) -1);
- if (r < 0) {
- error("IO Channel read error");
- goto failed;
- }
-
- if (r == 0) {
- error("No packet received on l2cap socket");
- goto failed;
- }
-
- errno = EPROTO;
-
- if ((size_t) r < sizeof(*rsp)) {
- error("Packet received is not bnep type");
- goto failed;
- }
-
- rsp = (void *) pkt;
- if (rsp->type != BNEP_CONTROL) {
- error("Packet received is not bnep type");
- goto failed;
- }
-
- if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
- return TRUE;
-
- r = ntohs(rsp->resp);
-
- if (r != BNEP_SUCCESS) {
- error("bnep failed");
- goto failed;
- }
-
- memset(&timeo, 0, sizeof(timeo));
- timeo.tv_sec = 0;
-
- setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
+ DBG("");
- if (bnep_connadd(sk, BNEP_SVC_PANU, nc->dev)) {
- error("%s could not be added", nc->dev);
+ if (err < 0) {
+ error("connect failed %s", strerror(-err));
goto failed;
}
- bnep_if_up(nc->dev);
+ info("%s connected", nc->dev);
+ memcpy(nc->dev, iface, sizeof(nc->dev));
btd_service_connecting_complete(nc->service, 0);
+
if (nc->connect)
local_connect_cb(nc, 0);
@@ -292,101 +219,30 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
nc->state = CONNECTED;
nc->dc_id = device_add_disconnect_watch(nc->peer->device, disconnect_cb,
- nc, NULL);
-
- info("%s connected", nc->dev);
- /* Start watchdog */
+ nc, NULL);
g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- (GIOFunc) bnep_watchdog_cb, nc);
+ bnep_watchdog_cb, nc);
g_io_channel_unref(nc->io);
nc->io = NULL;
- return FALSE;
+ return;
failed:
cancel_connection(nc, -EIO);
-
- return FALSE;
-}
-
-static int bnep_send_conn_req(struct network_conn *nc)
-{
- struct bnep_setup_conn_req *req;
- struct __service_16 *s;
- unsigned char pkt[BNEP_MTU];
- int fd;
-
- DBG("");
-
- /* Send request */
- req = (void *) pkt;
- req->type = BNEP_CONTROL;
- req->ctrl = BNEP_SETUP_CONN_REQ;
- req->uuid_size = 2; /* 16bit UUID */
- s = (void *) req->service;
- s->dst = htons(nc->id);
- s->src = htons(BNEP_SVC_PANU);
-
- fd = g_io_channel_unix_get_fd(nc->io);
- if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) {
- int err = -errno;
- error("bnep connection req send failed: %s", strerror(errno));
- return err;
- }
-
- nc->attempt_cnt++;
-
- return 0;
-}
-
-static gboolean bnep_conn_req_to(gpointer user_data)
-{
- struct network_conn *nc;
-
- nc = user_data;
- if (nc->attempt_cnt == CON_SETUP_RETRIES) {
- error("Too many bnep connection attempts");
- } else {
- error("bnep connection setup TO, retrying...");
- if (bnep_send_conn_req(nc) == 0)
- return TRUE;
- }
-
- cancel_connection(nc, -ETIMEDOUT);
-
- return FALSE;
-}
-
-static int bnep_connect(struct network_conn *nc)
-{
- int err;
-
- nc->attempt_cnt = 0;
-
- err = bnep_send_conn_req(nc);
- if (err < 0)
- return err;
-
- nc->timeout_source = g_timeout_add_seconds(CON_SETUP_TO,
- bnep_conn_req_to, nc);
-
- g_io_add_watch(nc->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- bnep_setup_cb, nc);
-
- return 0;
}
static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
{
struct network_conn *nc = data;
- int perr;
+ int sk, perr;
if (err) {
error("%s", err->message);
goto failed;
}
- perr = bnep_connect(nc);
+ sk = g_io_channel_unix_get_fd(nc->io);
+ perr = bnep_connect(sk, BNEP_SVC_PANU, nc->id, bnep_conn_cb, nc);
if (perr < 0) {
error("bnep connect(): %s (%d)", strerror(-perr), -perr);
goto failed;
@@ -692,8 +548,6 @@ int connection_register(struct btd_service *service)
nc = g_new0(struct network_conn, 1);
nc->id = id;
- memset(nc->dev, 0, sizeof(nc->dev));
- strcpy(nc->dev, "bnep%d");
nc->service = btd_service_ref(service);
nc->state = DISCONNECTED;
nc->peer = peer;
diff --git a/profiles/network/server.c b/profiles/network/server.c
index 0050b3037..3a7e52a4c 100644
--- a/profiles/network/server.c
+++ b/profiles/network/server.c
@@ -269,9 +269,6 @@ static int server_connadd(struct network_server *ns,
char devname[16];
int err, nsk;
- memset(devname, 0, sizeof(devname));
- strcpy(devname, "bnep%d");
-
nsk = g_io_channel_unix_get_fd(session->io);
err = bnep_connadd(nsk, dst_role, devname);
if (err < 0)