Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 18/60] Implement function to send md_abort_mdl_req
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-18-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |   48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 48 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 5419d54..6f6e08a 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -519,6 +519,38 @@ void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
 		g_free(con);
 }
 
+void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
+			mcap_mdl_del_cb abort_cb, gpointer user_data)
+{
+	struct mcap_mdl_op_cb *con;
+	struct mcap_mcl *mcl = mdl->mcl;
+	uint8_t *cmd;
+
+	if (mdl->state != MDL_WAITING) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+							"Mdl in invalid state");
+		return;
+	}
+
+	con = g_new0(struct mcap_mdl_op_cb, 1);
+	cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid);
+	mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
+	if (*err) {
+		g_free(con);
+		g_free(cmd);
+		return;
+	}
+
+	con->mdl = mdl;
+	con->cb.del = abort_cb;
+	con->user_data = user_data;
+
+	mcl->priv_data = con;
+
+	mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+									mcl);
+}
+
 static void update_mcl_state(struct mcap_mcl *mcl)
 {
 	GSList *l;
@@ -554,6 +586,22 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 	return NULL;
 }
 
+int mcap_mdl_get_fd(struct mcap_mdl *mdl)
+{
+	if ((!mdl) || (mdl->state != MDL_CONNECTED))
+		return -1;
+
+	return g_io_channel_unix_get_fd(mdl->dc);
+}
+
+uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl)
+{
+	if (!mdl)
+		return MCAP_MDLID_RESERVED;
+
+	return mdl->mdlid;
+}
+
 static void shutdown_mdl(struct mcap_mdl *mdl)
 {
 	mdl->state = MDL_CLOSED;
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 17/60] Implement function to send md_delete_mdl_req
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-17-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |  112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index a0f00af..5419d54 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -124,6 +124,38 @@ static void set_default_cb(struct mcap_mcl *mcl)
 	mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
 }
 
+static char *error2str(uint8_t rc)
+{
+	switch (rc) {
+	case MCAP_SUCCESS:
+		return "Success";
+	case MCAP_INVALID_OP_CODE:
+		return "Invalid Op Code";
+	case MCAP_INVALID_PARAM_VALUE:
+		return "Invalid Parameter Value";
+	case MCAP_INVALID_MDEP:
+		return "Invalid MDEP";
+	case MCAP_MDEP_BUSY:
+		return "MDEP Busy";
+	case MCAP_INVALID_MDL:
+		return "Invalid MDL";
+	case MCAP_MDL_BUSY:
+		return "MDL Busy";
+	case MCAP_INVALID_OPERATION:
+		return "Invalid Operation";
+	case MCAP_RESOURCE_UNAVAILABLE:
+		return "Resource Unavailable";
+	case MCAP_UNSPECIFIED_ERROR:
+		return "Unspecified Error";
+	case MCAP_REQUEST_NOT_SUPPORTED:
+		return "Request Not Supported";
+	case MCAP_CONFIGURATION_REJECTED:
+		return "Configuration Rejected";
+	default:
+		return "Unknown Response Code";
+	}
+}
+
 static void mcap_send_std_opcode(struct mcap_mcl *mcl, uint8_t *cmd,
 						uint32_t size, GError **err)
 {
@@ -407,6 +439,86 @@ void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
 									mcl);
 }
 
+static void send_delete_req(GError **err, struct mcap_mcl *mcl,
+				struct mcap_mdl_op_cb *con, uint16_t mdlid)
+{
+	uint8_t *cmd;
+
+	cmd = create_req(MCAP_MD_DELETE_MDL_REQ, mdlid);
+	mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
+	if (*err) {
+		g_free(cmd);
+		return;
+	}
+
+	mcl->priv_data = con;
+
+	mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+									mcl);
+}
+
+void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
+			mcap_mdl_del_cb delete_cb, gpointer user_data)
+{
+	GSList *l;
+	struct mcap_mdl *mdl;
+	struct mcap_mdl_op_cb *con;
+
+	DBG("MCL in state: %d", mcl->state);
+	if (!mcl->mdls) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+				"There are not MDLs created");
+		return;
+	}
+
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+		if (mdl->state != MDL_WAITING)
+			mdl->state = MDL_DELETING;
+	}
+
+	con = g_new0(struct mcap_mdl_op_cb, 1);
+	con->mdl = NULL;
+	con->cb.del = delete_cb;
+	con->user_data = user_data;
+
+	send_delete_req(err, mcl, con, MCAP_ALL_MDLIDS);
+	if (*err)
+		g_free(con);
+}
+
+void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
+			mcap_mdl_del_cb delete_cb, gpointer user_data)
+{
+	struct mcap_mcl *mcl= mdl->mcl;
+	struct mcap_mdl_op_cb *con;
+	GSList *l;
+
+	l = g_slist_find(mcl->mdls, mdl);
+
+	if (!l) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL,
+					"%s" , error2str(MCAP_INVALID_MDEP));
+		return;
+	}
+
+	if (mdl->state == MDL_WAITING) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+							"Mdl is not created");
+		return;
+	}
+	mdl->state = MDL_DELETING;
+
+	con = g_new0(struct mcap_mdl_op_cb, 1);
+	con->mdl = mdl;
+	con->cb.del = delete_cb;
+	con->user_data = user_data;
+
+	send_delete_req(err, mcl, con, mdl->mdlid);
+	if (*err)
+		g_free(con);
+}
+
 static void update_mcl_state(struct mcap_mcl *mcl)
 {
 	GSList *l;
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 16/60] Implement function to send md_reconnect_mdl_req
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-16-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index dc55cda..a0f00af 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -261,6 +261,20 @@ static uint16_t generate_mdlid(struct mcap_mcl *mcl)
 	return mdlid;
 }
 
+static uint8_t *create_req(uint8_t op, uint16_t mdl_id)
+{
+	uint8_t *req;
+	mcap_md_req *req_cmd;
+
+	req = g_malloc0(sizeof(mcap_md_req));
+
+	req_cmd = (mcap_md_req *)req;
+	req_cmd->op = op;
+	req_cmd->mdl = htons(mdl_id);
+
+	return req;
+}
+
 static uint8_t *create_mdl_req(uint16_t mdl_id, uint8_t mdep, uint8_t conf)
 {
 	uint8_t *req;
@@ -356,6 +370,43 @@ void mcap_req_mdl_creation(struct mcap_mcl *mcl,
 									mcl);
 }
 
+void mcap_req_mdl_reconnect(struct mcap_mdl *mdl,
+				GError **err,
+				mcap_mdl_operation_cb reconnect_cb,
+				gpointer user_data)
+{
+	struct mcap_mdl_op_cb *con;
+	struct mcap_mcl *mcl = mdl->mcl;
+	uint8_t *cmd;
+
+	if (mdl->state != MDL_CLOSED) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+					"MDL is not closed");
+		return;
+	}
+	con = g_new0(struct mcap_mdl_op_cb, 1);
+
+	cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid);
+	mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err);
+	if (*err) {
+		g_free(con);
+		g_free(cmd);
+		return;
+	}
+
+	mdl->state = MDL_WAITING;
+
+	con->mdl = mdl;
+	con->cb.op = reconnect_cb;
+	con->user_data = user_data;
+
+	mcl->state = MCL_ACTIVE;
+	mcl->priv_data = con;
+
+	mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+									mcl);
+}
+
 static void update_mcl_state(struct mcap_mcl *mcl)
 {
 	GSList *l;
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 15/60] Implement function to send md_create_mdl_req
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-15-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |  177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 177 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index aaac709..dc55cda 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -33,6 +33,7 @@
 #include "mcap_lib.h"
 #include "mcap_internal.h"
 
+#define RESPONSE_TIMER	2	/* seconds */
 #define MAX_CACHED	10	/* 10 devices */
 
 #define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
@@ -48,6 +49,17 @@ struct connect_mcl {
 	gpointer		user_data;	/* Callback user data */
 };
 
+typedef union {
+	mcap_mdl_operation_cb 		op;
+	mcap_mdl_operation_conf_cb	op_conf;
+	mcap_mdl_del_cb			del;
+} mcap_cb_type;
+
+struct mcap_mdl_op_cb {
+	struct mcap_mdl		*mdl;		/* MDL for this operation */
+	mcap_cb_type		cb;		/* Operation callback */
+	gpointer		user_data;	/* Callback user data */
+};
 
 /* MCAP finite state machine functions */
 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
@@ -60,6 +72,8 @@ static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
 	proc_req_active
 };
 
+static void mcap_cache_mcl(struct mcap_mcl *mcl);
+
 static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
 {
 	DBG("MCAP Unmanaged mdl connection");
@@ -110,6 +124,67 @@ static void set_default_cb(struct mcap_mcl *mcl)
 	mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
 }
 
+static void mcap_send_std_opcode(struct mcap_mcl *mcl, uint8_t *cmd,
+						uint32_t size, GError **err)
+{
+	if (mcl->state == MCL_IDLE) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+			"MCL is not connected");
+		return;
+	}
+
+	if (mcl->req != MCL_AVAILABLE) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE,
+					"Pending request");
+		return;
+	}
+
+	if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED,
+				    "Remote does not support standard opcodes");
+		return;
+	}
+
+	if (mcl->state == MCL_PENDING) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_OPERATION,
+			"Not Std Op. Codes can be sent in PENDING State");
+		return;
+	}
+
+	if (mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, size) < 0) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+				    "Command can't be sent, write error");
+		return;
+	}
+
+	mcl->lcmd = cmd;
+	mcl->req = MCL_WAITING_RSP;
+}
+
+static void mcap_notify_error(struct mcap_mcl *mcl, GError *err)
+{
+	struct mcap_mdl_op_cb *con = mcl->priv_data;
+
+	if (!con || !mcl->lcmd)
+		return;
+
+	switch (mcl->lcmd[0]){
+	case MCAP_MD_CREATE_MDL_REQ:
+		con->cb.op_conf(NULL, 0, err, con->user_data);
+		break;
+	case MCAP_MD_ABORT_MDL_REQ:
+	case MCAP_MD_DELETE_MDL_REQ:
+		con->cb.del(err, con->user_data);
+		break;
+	case MCAP_MD_RECONNECT_MDL_REQ:
+		con->cb.op(NULL, err, con->user_data);
+		break;
+	}
+
+	g_free(mcl->priv_data);
+	mcl->priv_data = NULL;
+}
+
 int mcap_send_data(int sock, const uint8_t *buf, uint32_t size)
 {
 	uint32_t sent = 0;
@@ -166,6 +241,42 @@ static int send5B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
 	return sent;
 }
 
+static uint16_t generate_mdlid(struct mcap_mcl *mcl)
+{
+	uint16_t mdlid = MCAP_MDLID_INITIAL;
+	struct mcap_mdl *mdl;
+	GSList *l;
+
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+		if (mdlid < mdl->mdlid)
+			break;
+		else
+			mdlid = mdl->mdlid + 1;
+	}
+
+	if (mdlid > MCAP_MDLID_FINAL)
+		return 0;
+
+	return mdlid;
+}
+
+static uint8_t *create_mdl_req(uint16_t mdl_id, uint8_t mdep, uint8_t conf)
+{
+	uint8_t *req;
+	mcap_md_create_mdl_req *req_mdl;
+
+	req = g_malloc0(sizeof(mcap_md_create_mdl_req));
+
+	req_mdl = (mcap_md_create_mdl_req *)req;
+	req_mdl->op = MCAP_MD_CREATE_MDL_REQ;
+	req_mdl->mdl = htons(mdl_id);
+	req_mdl->mdep = mdep;
+	req_mdl->conf = conf;
+
+	return req;
+}
+
 static gint compare_mdl(gconstpointer a, gconstpointer b)
 {
 	const struct mcap_mdl *mdla = a;
@@ -179,6 +290,72 @@ static gint compare_mdl(gconstpointer a, gconstpointer b)
 		return 1;
 }
 
+static gboolean wait_response_timer(gpointer data)
+{
+	struct mcap_mcl *mcl = data;
+
+	GError *gerr = NULL;
+
+	RELEASE_TIMER(mcl);
+
+	g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED,
+					"Timeout waiting response");
+
+	mcap_notify_error(mcl, gerr);
+
+	g_error_free(gerr);
+	mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+	mcap_cache_mcl(mcl);
+	return FALSE;
+}
+
+void mcap_req_mdl_creation(struct mcap_mcl *mcl,
+				uint8_t mdepid,
+				uint8_t conf,
+				GError **err,
+				mcap_mdl_operation_conf_cb connect_cb,
+				gpointer user_data)
+{
+	struct mcap_mdl *mdl;
+	struct mcap_mdl_op_cb *con;
+	uint8_t *cmd = NULL;
+	uint16_t id;
+
+	id = generate_mdlid(mcl);
+	if (!id) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED,
+					"Not more mdlids available");
+		return;
+	}
+
+	mdl = g_new0(struct mcap_mdl, 1);
+	mdl->mcl = mcl;
+	mdl->mdlid = id;
+	mdl->mdep_id = mdepid;
+	mdl->state = MDL_WAITING;
+
+	con = g_new0(struct mcap_mdl_op_cb, 1);
+	con->mdl = mdl;
+	con->cb.op_conf = connect_cb;
+	con->user_data = user_data;
+
+	cmd = create_mdl_req(id, mdepid, conf);
+	mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req), err);
+	if (*err) {
+		g_free(mdl);
+		g_free(con);
+		g_free(cmd);
+		return;
+	}
+
+	mcl->state = MCL_ACTIVE;
+	mcl->priv_data = con;
+
+	mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
+	mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer,
+									mcl);
+}
+
 static void update_mcl_state(struct mcap_mcl *mcl)
 {
 	GSList *l;
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 14/60] Implement set callbacks operation over MCLs
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-14-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |   82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 82 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 201f42c..aaac709 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -397,6 +397,88 @@ void mcap_mcl_unref(struct mcap_mcl *mcl)
 	mcap_mcl_release(mcl);
 }
 
+static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err,
+						McapMclCb cb1, va_list args)
+{
+	McapMclCb cb = cb1;
+	struct mcap_mdl_cb *c;
+
+	c = g_new0(struct mcap_mdl_cb, 1);
+
+	while (cb != MCAP_MDL_CB_INVALID) {
+		switch (cb) {
+		case MCAP_MDL_CB_CONNECTED:
+			c->mdl_connected = va_arg(args,
+				mcap_mdl_event_cb);
+			break;
+		case MCAP_MDL_CB_CLOSED:
+			c->mdl_closed = va_arg(args,
+				mcap_mdl_event_cb);
+			break;
+		case MCAP_MDL_CB_DELETED:
+			c->mdl_deleted = va_arg(args,
+				mcap_mdl_event_cb);
+			break;
+		case MCAP_MDL_CB_ABORTED:
+			c->mdl_aborted = va_arg(args,
+				mcap_mdl_event_cb);
+			break;
+		case MCAP_MDL_CB_REMOTE_CONN_REQ:
+			c->mdl_conn_req = va_arg(args,
+				mcap_remote_mdl_conn_req_cb);
+			break;
+		case MCAP_MDL_CB_REMOTE_RECONN_REQ:
+			c->mdl_reconn_req = va_arg(args,
+				mcap_remote_mdl_reconn_req_cb);
+			break;
+		default:
+			g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
+						"Unknown option %d", cb);
+			return FALSE;
+		}
+		cb = va_arg(args, int);
+	}
+
+	/* Set new callbacks */
+	if (c->mdl_connected)
+		mdl_cb->mdl_connected = c->mdl_connected;
+	if (c->mdl_closed)
+		mdl_cb->mdl_closed = c->mdl_closed;
+	if (c->mdl_deleted)
+		mdl_cb->mdl_deleted = c->mdl_deleted;
+	if (c->mdl_aborted)
+		mdl_cb->mdl_aborted = c->mdl_aborted;
+	if (c->mdl_conn_req)
+		mdl_cb->mdl_conn_req = c->mdl_conn_req;
+	if (c->mdl_reconn_req)
+		mdl_cb->mdl_reconn_req = c->mdl_reconn_req;
+
+	g_free(c);
+	return TRUE;
+}
+
+void mcap_mcl_set_cb(struct mcap_mcl *mcl, GError **gerr,
+					gpointer user_data, McapMclCb cb1, ...)
+{
+	va_list args;
+	gboolean ret;
+
+	va_start(args, cb1);
+	ret = parse_set_opts(mcl->cb, gerr, cb1, args);
+	va_end(args);
+
+	if (!ret)
+		return;
+
+	mcl->cb->user_data = user_data;
+	return;
+}
+
+bdaddr_t mcap_mcl_get_addr(struct mcap_mcl *mcl)
+{
+	return mcl->addr;
+}
+
 static void error_cmd_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
 	uint16_t mdlr;
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 13/60] Enable connect operation to a remote MCAP instances
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-13-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |  116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 116 insertions(+), 0 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 1d86c51..201f42c 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -42,6 +42,12 @@
 	__mcl->tid = 0;			\
 } while(0)
 
+struct connect_mcl {
+	struct mcap_mcl		*mcl;		/* MCL for this operation */
+	mcap_mcl_connect_cb	connect_cb;	/* Connect callback */
+	gpointer		user_data;	/* Callback user data */
+};
+
 
 /* MCAP finite state machine functions */
 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
@@ -800,6 +806,66 @@ fail:
 	return FALSE;
 }
 
+static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err,
+							gpointer user_data)
+{
+	char dstaddr[18];
+	struct connect_mcl *con = user_data;
+	struct mcap_mcl *aux, *mcl = con->mcl;
+	mcap_mcl_connect_cb connect_cb = con->connect_cb;
+	gpointer data = con->user_data;
+	GError *gerr = NULL;
+
+	g_free(con);
+
+	mcl->ctrl &= ~MCAP_CTRL_CONN;
+
+	if (conn_err) {
+		if (mcl->ctrl & MCAP_CTRL_FREE)
+			mcl->ms->mcl_uncached_cb(mcl, mcl->ms->user_data);
+		mcap_mcl_check_del(mcl);
+		connect_cb(NULL, conn_err, data);
+		return;
+	}
+
+	ba2str(&mcl->addr, dstaddr);
+
+	aux = find_mcl(mcl->ms->mcls, &mcl->addr);
+	if (aux) {
+		/* Double MCL connection case */
+		if (aux != mcl) {
+			/* This MCL was not in cache */
+			mcap_mcl_unref(mcl);
+		}
+		error("MCL error: Device %s is already connected", dstaddr);
+		g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
+				"MCL %s is already connected", dstaddr);
+		connect_cb(NULL, gerr, data);
+		g_error_free(gerr);
+		return;
+	}
+
+	mcl->state = MCL_CONNECTED;
+	mcl->role = MCL_INITIATOR;
+	mcl->req = MCL_AVAILABLE;
+	mcl->ctrl |= MCAP_CTRL_STD_OP;
+
+	if (mcl->ctrl & MCAP_CTRL_CACHED)
+		mcap_uncache_mcl(mcl);
+	else
+		mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
+
+	mcl->wid = g_io_add_watch(mcl->cc,
+				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+				(GIOFunc) mcl_control_cb, mcl);
+	connect_cb(mcl, gerr, data);
+
+	if (mcl->ref == 1) {
+		mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
+		mcap_mcl_unref(mcl);
+	}
+}
+
 static void connect_dc_event_cb(GIOChannel *chan, GError *err,
 							gpointer user_data)
 {
@@ -815,6 +881,56 @@ static void connect_dc_event_cb(GIOChannel *chan, GError *err,
 	mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
 }
 
+void mcap_create_mcl(struct mcap_instance *ms,
+				const bdaddr_t *addr,
+				uint16_t ccpsm,
+				GError **err,
+				mcap_mcl_connect_cb connect_cb,
+				gpointer user_data)
+{
+	struct mcap_mcl *mcl;
+	struct connect_mcl *con;
+
+	mcl = find_mcl(ms->mcls, addr);
+	if (mcl) {
+		g_set_error(err, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS,
+					"MCL is already connected.");
+		return;
+	}
+
+	mcl = find_mcl(ms->cached, addr);
+	if (!mcl) {
+		mcl = g_new0(struct mcap_mcl, 1);
+		mcl->ms = ms;
+		mcl->state = MCL_IDLE;
+		bacpy(&mcl->addr, addr);
+		set_default_cb(mcl);
+		mcl = mcap_mcl_ref(mcl);
+	} else
+		mcl->ctrl |= MCAP_CTRL_CONN;
+
+	con = g_new0(struct connect_mcl, 1);
+	con->mcl = mcl;
+	con->connect_cb = connect_cb;
+	con->user_data = user_data;
+
+	mcl->cc = bt_io_connect(BT_IO_L2CAP, mcap_connect_mcl_cb, con,
+				NULL, err,
+				BT_IO_OPT_SOURCE_BDADDR, &ms->src,
+				BT_IO_OPT_DEST_BDADDR, addr,
+				BT_IO_OPT_PSM, ccpsm,
+				BT_IO_OPT_MTU, MCAP_CC_MTU,
+				BT_IO_OPT_SEC_LEVEL, ms->sec,
+				BT_IO_OPT_INVALID);
+	if (*err) {
+		g_free(con);
+		mcl->ctrl &= ~MCAP_CTRL_CONN;
+		if (mcl->ctrl & MCAP_CTRL_FREE)
+			mcl->ms->mcl_uncached_cb(mcl, mcl->ms->user_data);
+		mcap_mcl_check_del(mcl);
+	}
+}
+
 static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
 {
 	struct mcap_instance *ms = user_data;
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 12/60] Managing connection of Data Channels
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-12-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |   71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 70 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index cf44472..1d86c51 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -754,6 +754,27 @@ static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 		proc_req[mcl->state](mcl, cmd, len);
 }
 
+static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+
+	struct mcap_mdl *mdl = data;
+	gboolean notify;
+
+	DBG("Close MDL %d", mdl->mdlid);
+
+	notify = (mdl->state == MDL_CONNECTED);
+	shutdown_mdl(mdl);
+
+	update_mcl_state(mdl->mcl);
+
+	if (notify) {
+		/*Callback to upper layer */
+		mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data);
+	}
+
+	return FALSE;
+}
+
 static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
 								gpointer data)
 {
@@ -779,9 +800,57 @@ fail:
 	return FALSE;
 }
 
+static void connect_dc_event_cb(GIOChannel *chan, GError *err,
+							gpointer user_data)
+{
+	struct mcap_mdl *mdl = user_data;
+	struct mcap_mcl *mcl = mdl->mcl;
+
+	mdl->state = MDL_CONNECTED;
+	mdl->dc = g_io_channel_ref(chan);
+	mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+						(GIOFunc) mdl_event_cb, mdl);
+
+	mcl->state = MCL_ACTIVE;
+	mcl->cb->mdl_connected(mdl, mcl->cb->user_data);
+}
+
 static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
 {
-	/* TODO */
+	struct mcap_instance *ms = user_data;
+	struct mcap_mcl *mcl;
+	struct mcap_mdl *mdl;
+	GError *err = NULL;
+	bdaddr_t dst;
+	GSList *l;
+
+	bt_io_get(chan, BT_IO_L2CAP, &err,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	mcl = find_mcl(ms->mcls, &dst);
+	if (!mcl || (mcl->state != MCL_PENDING))
+		goto drop;
+
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+		if (mdl->state == MDL_WAITING) {
+			if (!bt_io_accept(chan, connect_dc_event_cb, mdl, NULL,
+									&err)) {
+				error("MDL accept error %s", err->message);
+				g_error_free(err);
+				goto drop;
+			}
+			return;
+		}
+	}
+drop:
+	g_io_channel_shutdown(chan, TRUE, NULL);
 }
 
 static void connect_mcl_event_cb(GIOChannel *chan, GError *err,
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 11/60] Process commands in ACTIVE state
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-11-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 9f41c6b..cf44472 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -679,7 +679,19 @@ static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 
 static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
-	/* TODO */
+	switch (cmd[0]) {
+	case MCAP_MD_CREATE_MDL_REQ:
+		process_md_create_mdl_req(mcl, cmd, len);
+		break;
+	case MCAP_MD_RECONNECT_MDL_REQ:
+		process_md_reconnect_mdl_req(mcl, cmd, len);
+		break;
+	case MCAP_MD_DELETE_MDL_REQ:
+		process_md_delete_mdl_req(mcl, cmd, len);
+		break;
+	default:
+		error_cmd_rsp(mcl, cmd, len);
+	}
 }
 
 static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 10/60] Process md_abort_mdl_req in PENDING state
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-10-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |   50 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 49 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index d6a9760..9f41c6b 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -551,6 +551,51 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 	send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
 }
 
+static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+								uint32_t len)
+{
+	mcap_md_req *req;
+	GSList *l;
+	struct mcap_mdl *mdl, *del;
+	uint16_t mdl_id;
+
+	if (len != sizeof(mcap_md_req)) {
+		send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
+				MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+		return;
+	}
+
+	req = (mcap_md_req *)cmd;
+	mdl_id = ntohs(req->mdl);
+	mcl->state = MCL_CONNECTED;
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+		if ((mdl_id == mdl->mdlid) && (mdl->state == MDL_WAITING)) {
+			del = mdl;
+			if (mcl->state != MCL_CONNECTED)
+				break;
+			continue;
+		}
+		if ((mdl->state == MDL_CONNECTED) && (mcl->state != MCL_ACTIVE))
+			mcl->state = MCL_ACTIVE;
+
+		if ((del) && (mcl->state == MCL_ACTIVE))
+			break;
+	}
+
+	if (!del) {
+		send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL,
+									mdl_id);
+		return;
+	}
+
+	mcl->cb->mdl_aborted(del, mcl->cb->user_data);
+
+	mcl->mdls = g_slist_remove(mcl->mdls, del);
+	g_free(del);
+	send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id);
+}
+
 static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 								uint32_t len)
 {
@@ -626,7 +671,10 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 
 static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
-	/* TODO */
+	if (cmd[0] == MCAP_MD_ABORT_MDL_REQ)
+		process_md_abort_mdl_req(mcl, cmd, len);
+	else
+		error_cmd_rsp(mcl, cmd, len);
 }
 
 static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 09/60] Process md_delete_mdl_req in CONNECTED state
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-9-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |   88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 87 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index da7edfb..d6a9760 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -173,6 +173,26 @@ static gint compare_mdl(gconstpointer a, gconstpointer b)
 		return 1;
 }
 
+static void update_mcl_state(struct mcap_mcl *mcl)
+{
+	GSList *l;
+	struct mcap_mdl *mdl;
+
+	if (mcl->state == MCL_PENDING)
+		return;
+
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+
+		if (mdl->state == MDL_CONNECTED) {
+			mcl->state = MCL_ACTIVE;
+			return;
+		}
+	}
+
+	mcl->state = MCL_CONNECTED;
+}
+
 static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 {
 	GSList *l;
@@ -406,6 +426,17 @@ static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
 	return NULL;
 }
 
+static void mcap_delete_mdl(gpointer elem, gpointer user_data)
+{
+	struct mcap_mdl *mdl = elem;
+	gboolean notify = *(gboolean *)user_data;
+
+	shutdown_mdl(mdl);
+	if (notify)
+		mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data);
+	g_free(mdl);
+}
+
 static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 								uint32_t len)
 {
@@ -520,6 +551,61 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 	send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
 }
 
+static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+								uint32_t len)
+{
+	mcap_md_req *req;
+	struct mcap_mdl *mdl, *aux;
+	uint16_t mdlid;
+	gboolean notify;
+	GSList *l;
+
+	if (len != sizeof(mcap_md_req)) {
+		send4B_cmd(mcl, MCAP_MD_ABORT_MDL_RSP,
+				MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+		return;
+	}
+
+	req = (mcap_md_req *)cmd;
+	mdlid = ntohs(req->mdl);
+	if (mdlid == MCAP_ALL_MDLIDS) {
+		notify = FALSE;
+		g_slist_foreach(mcl->mdls, mcap_delete_mdl, &notify);
+		g_slist_free(mcl->mdls);
+		mcl->mdls = NULL;
+		mcl->state = MCL_CONNECTED;
+		/* NULL mdl means ALL_MDLS */
+		mcl->cb->mdl_deleted(NULL, mcl->cb->user_data);
+		goto resp;
+	}
+
+	if ((mdlid < MCAP_MDLID_INITIAL) || (mdlid > MCAP_MDLID_FINAL)) {
+		send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
+									mdlid);
+		return;
+	}
+
+	for (l = mcl->mdls, mdl = NULL; l; l = l->next) {
+		aux = l->data;
+		if (aux->mdlid == mdlid) {
+			mdl = aux;
+			break;
+		}
+	}
+
+	if (!mdl || (mdl->state == MDL_WAITING)) {
+		send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL,
+									mdlid);
+		return;
+	}
+	mcl->mdls = g_slist_remove(mcl->mdls, mdl);
+	update_mcl_state(mcl);
+	notify = TRUE;
+	mcap_delete_mdl(mdl, &notify);
+resp:
+	send4B_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid);
+}
+
 /* Function used to process commands depending of MCL state */
 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
@@ -531,7 +617,7 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 		process_md_reconnect_mdl_req(mcl, cmd, len);
 		break;
 	case MCAP_MD_DELETE_MDL_REQ:
-		/*process_md_delete_mdl_req(mcl, cmd, len);*/
+		process_md_delete_mdl_req(mcl, cmd, len);
 		break;
 	default:
 		error_cmd_rsp(mcl, cmd, len);
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 08/60] Process md_reconnect_mdl_req in CONNECTED state
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-8-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |   44 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 43 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index b2d1d86..da7edfb 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -478,6 +478,48 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
 	send5B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id, conf);
 }
 
+static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+								uint32_t len)
+{
+	mcap_md_req *req;
+	struct mcap_mdl *mdl;
+	uint16_t mdl_id;
+	uint8_t rsp;
+
+	if (len != sizeof(mcap_md_req)) {
+		send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
+				MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+		return;
+	}
+
+	req = (mcap_md_req *)cmd;
+	mdl_id = ntohs(req->mdl);
+
+	mdl = get_mdl(mcl, mdl_id);
+	if (!mdl) {
+		send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP,
+						MCAP_INVALID_MDL, mdl_id);
+		return;
+	}
+
+	/* Callback to upper layer */
+	rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data);
+	if (mcl->state == MCL_IDLE)
+		return;
+
+	if (rsp != MCAP_SUCCESS) {
+		send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id);
+		return;
+	}
+
+	if (mdl->state == MDL_CONNECTED)
+		shutdown_mdl(mdl);
+
+	mdl->state = MDL_WAITING;
+	mcl->state = MCL_PENDING;
+	send4B_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id);
+}
+
 /* Function used to process commands depending of MCL state */
 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
@@ -486,7 +528,7 @@ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 		process_md_create_mdl_req(mcl, cmd, len);
 		break;
 	case MCAP_MD_RECONNECT_MDL_REQ:
-		/*process_md_reconnect_mdl_req(mcl, cmd, len);*/
+		process_md_reconnect_mdl_req(mcl, cmd, len);
 		break;
 	case MCAP_MD_DELETE_MDL_REQ:
 		/*process_md_delete_mdl_req(mcl, cmd, len);*/
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 07/60] Process md_create_mdl_req in CONNECTED state
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-7-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |  156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 155 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 0bc5035..b2d1d86 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -139,6 +139,40 @@ static int send4B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
 	return sent;
 }
 
+static int send5B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
+						uint16_t mdl, uint8_t param)
+{
+	uint8_t *rsp;
+	mcap5B_rsp *suc;
+	int sent;
+
+	rsp = g_malloc0(sizeof(mcap5B_rsp));
+
+	suc = (mcap5B_rsp *)rsp;
+	suc->op = oc;
+	suc->rc = rc;
+	suc->mdl = htons(mdl);
+	suc->param = param;
+
+	sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), rsp,
+							sizeof(mcap5B_rsp));
+	g_free(rsp);
+	return sent;
+}
+
+static gint compare_mdl(gconstpointer a, gconstpointer b)
+{
+	const struct mcap_mdl *mdla = a;
+	const struct mcap_mdl *mdlb = b;
+
+	if (mdla->mdlid == mdlb->mdlid)
+		return 0;
+	else if (mdla->mdlid < mdlb->mdlid)
+		return -1;
+	else
+		return 1;
+}
+
 static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 {
 	GSList *l;
@@ -337,9 +371,129 @@ void mcap_mcl_unref(struct mcap_mcl *mcl)
 	mcap_mcl_release(mcl);
 }
 
+static void error_cmd_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	uint16_t mdlr;
+
+	if (cmd[0] <= MCAP_MD_DELETE_MDL_RSP) {
+		/* Standard Op Code request is invalid in current state */
+		error("Invalid cmd received (op code = %d) in state %d",
+							cmd[0],	mcl->state);
+		/* Get previously mdlid sent to generate an appropriate
+		 * response if it is possible */
+		mdlr = len < sizeof(mcap_md_req) ? MCAP_MDLID_RESERVED :
+					ntohs(((mcap_md_req *)cmd)->mdl);
+		send4B_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr);
+	} else {
+		error("Unknown cmd request received (op code = %d) in state %d",
+							cmd[0], mcl->state);
+		send4B_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE,
+							MCAP_MDLID_RESERVED);
+	}
+}
+
+static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid)
+{
+	GSList *l;
+	struct mcap_mdl *mdl;
+
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+		if (mdlid == mdl->mdlid)
+			return mdl;
+	}
+
+	return NULL;
+}
+
+static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd,
+								uint32_t len)
+{
+	mcap_md_create_mdl_req *req;
+	struct mcap_mdl *mdl;
+	uint16_t mdl_id;
+	uint8_t mdep_id;
+	uint8_t cfga, conf;
+	uint8_t rsp;
+
+	if (len != sizeof(mcap_md_create_mdl_req)) {
+		send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP,
+				MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED);
+		return;
+	}
+
+	req = (mcap_md_create_mdl_req *)cmd;
+
+	mdl_id = ntohs(req->mdl);
+	if ((mdl_id < MCAP_MDLID_INITIAL) || (mdl_id > MCAP_MDLID_FINAL)) {
+		send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL,
+									mdl_id);
+		return;
+	}
+
+	mdep_id = req->mdep;
+	if (mdep_id > MCAP_MDEPID_FINAL) {
+		send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP,
+									mdl_id);
+		return;
+	}
+
+	cfga = conf = req->conf;
+	/* Callback to upper layer */
+	rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf,
+							mcl->cb->user_data);
+	if (mcl->state == MCL_IDLE) {
+		/* MCL has been closed int the callback */
+		return;
+	}
+
+	if ((cfga != 0) && (cfga != conf)) {
+		/* Remote device set default configuration but upper profile */
+		/* has changed it. Protocol Error: force closing the MCL by */
+		/* remote device using UNSPECIFIED_ERROR response */
+		send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_UNSPECIFIED_ERROR,
+									mdl_id);
+		return;
+	}
+	if (rsp != MCAP_SUCCESS) {
+		send4B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id);
+		return;
+	}
+
+	mdl = get_mdl(mcl, mdl_id);
+	if (!mdl) {
+		mdl = g_malloc0(sizeof(struct mcap_mdl));
+		mdl->mcl = mcl;
+		mdl->mdlid = mdl_id;
+	} else if (mdl->state == MDL_CONNECTED) {
+		/* MCAP specification says that we should close the MCL if
+		 * it is open when we receive a MD_CREATE_MDL_REQ */
+		shutdown_mdl(mdl);
+	}
+	mdl->mdep_id = mdep_id;
+	mdl->state = MDL_WAITING;
+	mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl);
+
+	mcl->state = MCL_PENDING;
+	send5B_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id, conf);
+}
+
+/* Function used to process commands depending of MCL state */
 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
 {
-	/* TODO */
+	switch (cmd[0]) {
+	case MCAP_MD_CREATE_MDL_REQ:
+		process_md_create_mdl_req(mcl, cmd, len);
+		break;
+	case MCAP_MD_RECONNECT_MDL_REQ:
+		/*process_md_reconnect_mdl_req(mcl, cmd, len);*/
+		break;
+	case MCAP_MD_DELETE_MDL_REQ:
+		/*process_md_delete_mdl_req(mcl, cmd, len);*/
+		break;
+	default:
+		error_cmd_rsp(mcl, cmd, len);
+	}
 }
 
 static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 06/60] Release MCAP instances
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-6-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |   31 ++++++++++++++++++++++++++++++-
 1 files changed, 30 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 8551ddf..0bc5035 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -603,5 +603,34 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
 
 void mcap_release_instance(struct mcap_instance *ms)
 {
-	/* TODO */
+	GSList *l;
+
+	if (!ms)
+		return;
+
+	if (ms->ccio) {
+		g_io_channel_shutdown(ms->ccio, TRUE, NULL);
+		g_io_channel_unref(ms->ccio);
+		ms->ccio = NULL;
+	}
+
+	if (ms->dcio) {
+		g_io_channel_shutdown(ms->dcio, TRUE, NULL);
+		g_io_channel_unref(ms->dcio);
+		ms->dcio = NULL;
+	}
+
+	for (l = ms->mcls; l; l = l->next) {
+		mcap_mcl_shutdown(l->data);
+		mcap_mcl_unref(l->data);
+	}
+	g_slist_free(ms->mcls);
+	ms->mcls = NULL;
+
+	for (l = ms->cached; l; l = l->next)
+		mcap_mcl_unref(l->data);
+	g_slist_free(ms->cached);
+	ms->cached = NULL;
+
+	g_free(ms);
 }
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 05/60] Save and restore state of MCLs
From: Santiago Carot-Nemesio @ 2010-07-22  8:52 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-5-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |  158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 154 insertions(+), 4 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 5197fde..8551ddf 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -33,8 +33,16 @@
 #include "mcap_lib.h"
 #include "mcap_internal.h"
 
+#define MAX_CACHED	10	/* 10 devices */
+
 #define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
 
+#define RELEASE_TIMER(__mcl) do {	\
+	g_source_remove(__mcl->tid);	\
+	__mcl->tid = 0;			\
+} while(0)
+
+
 /* MCAP finite state machine functions */
 static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
 static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
@@ -146,24 +154,166 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 	return NULL;
 }
 
+static void shutdown_mdl(struct mcap_mdl *mdl)
+{
+	mdl->state = MDL_CLOSED;
+
+	g_source_remove(mdl->wid);
+
+	if (mdl->dc) {
+		g_io_channel_shutdown(mdl->dc, TRUE, NULL);
+		g_io_channel_unref(mdl->dc);
+		mdl->dc = NULL;
+	}
+}
+
+static void mcap_free_mdls(struct mcap_mcl *mcl, gboolean save)
+{
+	GSList *l;
+	struct mcap_mdl *mdl;
+
+	if (!mcl->mdls)
+		return;
+
+	for (l = mcl->mdls; l; l = l->next) {
+		mdl = l->data;
+		shutdown_mdl(mdl);
+		if (!save)
+			g_free(mdl);
+	}
+
+	if (!save) {
+		g_slist_free(mcl->mdls);
+		mcl->mdls = NULL;
+	}
+}
+
+static void close_mcl(struct mcap_mcl *mcl, gboolean save)
+{
+	gboolean store = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && save);
+
+	if (mcl->tid) {
+		RELEASE_TIMER(mcl);
+	}
+
+	if (mcl->cc) {
+		g_io_channel_shutdown(mcl->cc, TRUE, NULL);
+		g_io_channel_unref(mcl->cc);
+		mcl->cc = NULL;
+	}
+
+	g_source_remove(mcl->wid);
+	if (mcl->lcmd) {
+		g_free(mcl->lcmd);
+		mcl->lcmd = NULL;
+	}
+
+	if (mcl->priv_data) {
+		g_free(mcl->priv_data);
+		mcl->priv_data = NULL;
+	}
+
+	mcap_free_mdls(mcl, store);
+
+	if (mcl->cb && !store) {
+		g_free(mcl->cb);
+		mcl->cb = NULL;
+	}
+
+	mcl->state = MCL_IDLE;
+
+	if (store)
+		return;
+
+	g_free(mcl);
+}
+
+static void mcap_mcl_shutdown(struct mcap_mcl *mcl)
+{
+	close_mcl(mcl, TRUE);
+}
+
 static void mcap_mcl_release(struct mcap_mcl *mcl)
 {
-	/* TODO */
+	close_mcl(mcl, FALSE);
 }
 
 static void mcap_mcl_check_del(struct mcap_mcl *mcl)
 {
-	/* TODO */
+	if (mcl->ctrl & MCAP_CTRL_CACHED)
+		mcap_mcl_shutdown(mcl);
+	else
+		mcap_mcl_unref(mcl);
 }
 
 static void mcap_cache_mcl(struct mcap_mcl *mcl)
 {
-	/* TODO */
+	GSList *l;
+	struct mcap_mcl *last;
+	int len;
+
+	if (mcl->ctrl & MCAP_CTRL_CACHED)
+		return;
+
+	mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
+
+	if ((mcl->ctrl & MCAP_CTRL_NOCACHE) || (mcl->ref < 2)) {
+		mcap_mcl_unref(mcl);
+		return;
+	}
+
+	DBG("Caching MCL");
+
+	len = g_slist_length(mcl->ms->cached);
+	if (len == MAX_CACHED) {
+		/* Remove the latest cached mcl */
+		l = g_slist_last(mcl->ms->cached);
+		last = l->data;
+		mcl->ms->cached = g_slist_remove(mcl->ms->cached, last);
+		last->ctrl &= ~MCAP_CTRL_CACHED;
+		if (last->ctrl & MCAP_CTRL_CONN) {
+			/* If connection process is not success this MCL will be
+			 * freed next time that close_mcl is invoked */
+			last->ctrl |= MCAP_CTRL_FREE;
+		} else {
+			last->ms->mcl_uncached_cb(last, last->ms->user_data);
+			mcap_mcl_unref(last);
+		}
+	}
+
+	mcl->ms->cached = g_slist_prepend(mcl->ms->cached, mcl);
+	mcl->ctrl |= MCAP_CTRL_CACHED;
+	mcap_mcl_shutdown(mcl);
 }
 
 static void mcap_uncache_mcl(struct mcap_mcl *mcl)
 {
-	/* TODO */
+	if (!(mcl->ctrl & MCAP_CTRL_CACHED))
+		return;
+
+	DBG("Got MCL from cache");
+
+	mcl->ms->cached = g_slist_remove(mcl->ms->cached, mcl);
+	mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
+	mcl->ctrl &= ~MCAP_CTRL_CACHED;
+	mcl->ctrl &= ~MCAP_CTRL_FREE;
+}
+
+void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache)
+{
+	if (!mcl)
+		return;
+
+	if (mcl->cc) {
+		g_io_channel_shutdown(mcl->cc, TRUE, NULL);
+		g_io_channel_unref(mcl->cc);
+		mcl->cc = NULL;
+	}
+
+	mcl->state = MCL_IDLE;
+
+	if (!cache)
+		mcl->ctrl |= MCAP_CTRL_NOCACHE;
 }
 
 struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 04/60] Process events over Control Channels
From: Santiago Carot-Nemesio @ 2010-07-22  8:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-4-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |  145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 144 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index ea00d73..5197fde 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -35,6 +35,17 @@
 
 #define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
 
+/* MCAP finite state machine functions */
+static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
+static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
+static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l);
+
+static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = {
+	proc_req_connected,
+	proc_req_pending,
+	proc_req_active
+};
+
 static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
 {
 	DBG("MCAP Unmanaged mdl connection");
@@ -85,6 +96,41 @@ static void set_default_cb(struct mcap_mcl *mcl)
 	mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
 }
 
+int mcap_send_data(int sock, const uint8_t *buf, uint32_t size)
+{
+	uint32_t sent = 0;
+
+	while (sent < size) {
+		int n = send(sock, buf + sent, size - sent, 0);
+		if (n < 0)
+			return -1;
+		sent += n;
+	}
+	return 0;
+}
+
+static int send4B_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc,
+								uint16_t mdl)
+{
+	uint8_t *rsp;
+	mcap4B_rsp *rsp_err;
+	int sent;
+
+
+	rsp = g_malloc0(sizeof(mcap4B_rsp));
+
+	rsp_err = (mcap4B_rsp *)rsp;
+	rsp_err->op = oc;
+	rsp_err->rc = rc;
+	rsp_err->mdl = htons (mdl);
+
+	sent = mcap_send_data(g_io_channel_unix_get_fd(mcl->cc),
+					rsp,
+					sizeof(mcap4B_rsp));
+	g_free(rsp);
+	return sent;
+}
+
 static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 {
 	GSList *l;
@@ -110,6 +156,11 @@ static void mcap_mcl_check_del(struct mcap_mcl *mcl)
 	/* TODO */
 }
 
+static void mcap_cache_mcl(struct mcap_mcl *mcl)
+{
+	/* TODO */
+}
+
 static void mcap_uncache_mcl(struct mcap_mcl *mcl)
 {
 	/* TODO */
@@ -136,11 +187,103 @@ void mcap_mcl_unref(struct mcap_mcl *mcl)
 	mcap_mcl_release(mcl);
 }
 
+static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO */
+}
+
+static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO */
+}
+
+static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO */
+}
+
+static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	/* TODO */
+}
+
+static void rsend_req(struct mcap_mcl *mcl)
+{
+	uint8_t *cmd = mcl->lcmd;
+	int len;
+
+	if (!cmd)
+		return;
+
+	switch (cmd[0]) {
+	case MCAP_MD_RECONNECT_MDL_REQ:
+	case MCAP_MD_ABORT_MDL_REQ:
+	case MCAP_MD_DELETE_MDL_REQ:
+		len = 3;
+		break;
+	case MCAP_MD_CREATE_MDL_REQ:
+		len = 5;
+		break;
+	default:
+		return;
+	}
+
+	mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, len);
+}
+
+static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
+{
+	if ((cmd[0] >= MCAP_MD_SYNC_CAP_REQ) &&
+					(cmd[0] <= MCAP_MD_SYNC_INFO_IND)) {
+		send4B_cmd(mcl, cmd[0], MCAP_REQUEST_NOT_SUPPORTED,
+							MCAP_MDLID_RESERVED);
+		return;
+	}
+
+	if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) {
+		/* In case the remote device doesn't work correctly */
+		error("Remote device does not support opcodes, cmd ignored");
+		return;
+	}
+
+	if (mcl->req == MCL_WAITING_RSP) {
+		if (cmd[0] & 0x01) {
+			/* Request arrived when a response is expected */
+			if (mcl->role == MCL_INITIATOR)
+				/* ignore */
+				return;
+			proc_req[mcl->state](mcl, cmd, len);
+			/* Initiator will ignore our last request => re-send */
+			rsend_req(mcl);
+			return;
+		}
+		proc_response(mcl, cmd, len);
+	} else if (cmd[0] & 0x01)
+		proc_req[mcl->state](mcl, cmd, len);
+}
+
 static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
 								gpointer data)
 {
 
-	/* TODO */
+	struct mcap_mcl *mcl = data;
+	int sk, len;
+	uint8_t buf[MCAP_CC_MTU];
+
+	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+		goto fail;
+
+	sk = g_io_channel_unix_get_fd(chan);
+	len = recv(sk, buf, sizeof(buf), 0);
+	if (len < 0)
+		goto fail;
+
+	proc_cmd(mcl, buf, (uint32_t)len);
+	return TRUE;
+fail:
+	if (mcl->state != MCL_IDLE)
+		mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data);
+	mcap_cache_mcl(mcl);
 	return FALSE;
 }
 
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 03/60] Initial work to process incomming connection of MCLs
From: Santiago Carot-Nemesio @ 2010-07-22  8:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-3-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |  193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 192 insertions(+), 1 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index d47b451..ea00d73 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -35,14 +35,205 @@
 
 #define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
 
+static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data)
+{
+	DBG("MCAP Unmanaged mdl connection");
+}
+
+static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data)
+{
+	DBG("MCAP Unmanaged mdl closed");
+}
+
+static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data)
+{
+	DBG("MCAP Unmanaged mdl deleted");
+}
+
+static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data)
+{
+	DBG("MCAP Unmanaged mdl aborted");
+}
+
+static uint8_t default_mdl_conn_req_cb(struct mcap_mcl *mcl,
+						uint8_t mdepid, uint16_t mdlid,
+						uint8_t *conf, gpointer data)
+{
+	DBG("MCAP mdl remote connection aborted");
+	/* Due to this callback isn't managed this request won't be supported */
+	return MCAP_REQUEST_NOT_SUPPORTED;
+}
+
+static uint8_t default_mdl_reconn_req_cb(struct mcap_mdl *mdl,
+						gpointer data)
+{
+	DBG("MCAP mdl remote reconnection aborted");
+	/* Due to this callback isn't managed this request won't be supported */
+	return MCAP_REQUEST_NOT_SUPPORTED;
+}
+
+static void set_default_cb(struct mcap_mcl *mcl)
+{
+	if (!mcl->cb)
+		mcl->cb = g_new0(struct mcap_mdl_cb, 1);
+
+	mcl->cb->mdl_connected = default_mdl_connected_cb;
+	mcl->cb->mdl_closed = default_mdl_closed_cb;
+	mcl->cb->mdl_deleted = default_mdl_deleted_cb;
+	mcl->cb->mdl_aborted = default_mdl_aborted_cb;
+	mcl->cb->mdl_conn_req = default_mdl_conn_req_cb;
+	mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb;
+}
+
+static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
+{
+	GSList *l;
+	struct mcap_mcl *mcl;
+
+	for (l = list; l; l = l->next) {
+		mcl = l->data;
+
+		if (!bacmp(&mcl->addr, addr))
+			return mcl;
+	}
+
+	return NULL;
+}
+
+static void mcap_mcl_release(struct mcap_mcl *mcl)
+{
+	/* TODO */
+}
+
+static void mcap_mcl_check_del(struct mcap_mcl *mcl)
+{
+	/* TODO */
+}
+
+static void mcap_uncache_mcl(struct mcap_mcl *mcl)
+{
+	/* TODO */
+}
+
+struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl)
+{
+	mcl->ref++;
+
+	DBG("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref);
+
+	return mcl;
+}
+
+void mcap_mcl_unref(struct mcap_mcl *mcl)
+{
+	mcl->ref--;
+
+	DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref);
+
+	if (mcl->ref > 0)
+		return;
+
+	mcap_mcl_release(mcl);
+}
+
+static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond,
+								gpointer data)
+{
+
+	/* TODO */
+	return FALSE;
+}
+
 static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
 {
 	/* TODO */
 }
 
+static void connect_mcl_event_cb(GIOChannel *chan, GError *err,
+							gpointer user_data)
+{
+	struct mcap_mcl *mcl = user_data;
+	gboolean reconn;
+
+	if (err) {
+		mcap_mcl_check_del(mcl);
+		return;
+	}
+
+	mcl->state = MCL_CONNECTED;
+	mcl->role = MCL_ACCEPTOR;
+	mcl->req = MCL_AVAILABLE;
+	mcl->cc = g_io_channel_ref(chan);
+	mcl->ctrl |= MCAP_CTRL_STD_OP;
+
+	reconn = (mcl->ctrl & MCAP_CTRL_CACHED);
+	if (reconn)
+		mcap_uncache_mcl(mcl);
+	else
+		mcl->ms->mcls = g_slist_prepend(mcl->ms->mcls, mcl);
+
+	mcl->wid = g_io_add_watch(mcl->cc,
+			G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+			(GIOFunc) mcl_control_cb, mcl);
+
+	/* Callback to report new MCL */
+	if (reconn)
+		mcl->ms->mcl_reconnected_cb(mcl, mcl->ms->user_data);
+	else
+		mcl->ms->mcl_connected_cb(mcl, mcl->ms->user_data);
+
+	if (mcl->ref == 1) {
+		mcl->ms->mcls = g_slist_remove(mcl->ms->mcls, mcl);
+		mcap_mcl_unref(mcl);
+	}
+}
+
 static void confirm_mcl_event_cb(GIOChannel *chan, gpointer user_data)
 {
-	/* TODO */
+	struct mcap_instance *ms = user_data;
+	struct mcap_mcl *mcl;
+	bdaddr_t dst;
+	char address[18], srcstr[18];
+	GError *err = NULL;
+
+	bt_io_get(chan, BT_IO_L2CAP, &err,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_DEST, address,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	ba2str(&ms->src, srcstr);
+	mcl = find_mcl(ms->mcls, &dst);
+	if (mcl) {
+		error("Control channel already created with %s on adapter %s",
+				address, srcstr);
+		goto drop;
+	}
+
+	mcl = find_mcl(ms->cached, &dst);
+	if (!mcl) {
+		mcl = g_new0(struct mcap_mcl, 1);
+		mcl->ms = ms;
+		bacpy(&mcl->addr, &dst);
+		set_default_cb(mcl);
+		mcl = mcap_mcl_ref(mcl);
+	}
+
+	if (!bt_io_accept(chan, connect_mcl_event_cb, mcl, NULL, &err)) {
+		error("mcap accept error: %s", err->message);
+		if (!(mcl->ctrl & MCAP_CTRL_CACHED))
+			mcap_mcl_unref(mcl);
+		g_error_free(err);
+		goto drop;
+	}
+
+	return;
+drop:
+	g_io_channel_shutdown(chan, TRUE, NULL);
 }
 
 struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 02/60] Initial work to create MCAP instances
From: Santiago Carot-Nemesio @ 2010-07-22  8:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-2-git-send-email-sancane@gmail.com>

---
 mcap/mcap.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/mcap/mcap.c b/mcap/mcap.c
index 8bd2ad2..d47b451 100644
--- a/mcap/mcap.c
+++ b/mcap/mcap.c
@@ -33,6 +33,18 @@
 #include "mcap_lib.h"
 #include "mcap_internal.h"
 
+#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark")
+
+static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data)
+{
+	/* TODO */
+}
+
+static void confirm_mcl_event_cb(GIOChannel *chan, gpointer user_data)
+{
+	/* TODO */
+}
+
 struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
 					BtIOSecLevel sec,
 					uint16_t ccpsm,
@@ -44,8 +56,65 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
 					mcap_mcl_event_cb mcl_uncached,
 					gpointer user_data)
 {
-	/* TODO */
-	return NULL;
+	struct mcap_instance *ms;
+
+	if (sec < BT_IO_SEC_MEDIUM) {
+		g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
+				"Security level can't be minor of %d",
+				BT_IO_SEC_MEDIUM);
+		return NULL;
+	}
+
+	if (!(mcl_connected && mcl_reconnected &&
+			mcl_disconnected && mcl_uncached)) {
+		g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
+				"The callbacks can't be null");
+		return NULL;
+	}
+
+	ms = g_new0(struct mcap_instance, 1);
+
+	adapter_get_address(btd_adapter, &ms->src);
+
+	ms->sec = sec;
+	ms->mcl_connected_cb = mcl_connected;
+	ms->mcl_reconnected_cb = mcl_reconnected;
+	ms->mcl_disconnected_cb = mcl_disconnected;
+	ms->mcl_uncached_cb = mcl_uncached;
+	ms->user_data = user_data;
+
+	/* Listen incoming connections in control channel */
+	ms->ccio = bt_io_listen(BT_IO_L2CAP, NULL, confirm_mcl_event_cb, ms,
+				NULL, gerr,
+				BT_IO_OPT_SOURCE_BDADDR, &ms->src,
+				BT_IO_OPT_PSM, ccpsm,
+				BT_IO_OPT_MTU, MCAP_CC_MTU,
+				BT_IO_OPT_SEC_LEVEL, sec,
+				BT_IO_OPT_INVALID);
+	if (!ms->ccio) {
+		error("%s", (*gerr)->message);
+		g_free(ms);
+		return NULL;
+	}
+
+	/* Listen incoming connections in data channels */
+	ms->dcio = bt_io_listen(BT_IO_L2CAP, NULL, confirm_dc_event_cb, ms,
+				NULL, gerr,
+				BT_IO_OPT_SOURCE_BDADDR, &ms->src,
+				BT_IO_OPT_PSM, dcpsm,
+				BT_IO_OPT_MTU, MCAP_DC_MTU,
+				BT_IO_OPT_SEC_LEVEL, sec,
+				BT_IO_OPT_INVALID);
+	if (!ms->dcio) {
+		g_io_channel_shutdown(ms->ccio, TRUE, NULL);
+		g_io_channel_unref(ms->ccio);
+		ms->ccio = NULL;
+		error("%s", (*gerr)->message);
+		g_free(ms);
+		return NULL;
+	}
+
+	return ms;
 }
 
 void mcap_release_instance(struct mcap_instance *ms)
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 01/60] Initial support for MCAP
From: Santiago Carot-Nemesio @ 2010-07-22  8:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Santiago Carot-Nemesio
In-Reply-To: <1279788733-2324-1-git-send-email-sancane@gmail.com>

---
 Makefile.am          |   13 ++++-
 acinclude.m4         |    6 ++
 mcap/mcap.c          |   54 ++++++++++++++++
 mcap/mcap.h          |  165 ++++++++++++++++++++++++++++++++++++++++++++++++++
 mcap/mcap_internal.h |  118 +++++++++++++++++++++++++++++++++++
 mcap/mcap_lib.h      |  161 ++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 516 insertions(+), 1 deletions(-)
 create mode 100644 mcap/mcap.c
 create mode 100644 mcap/mcap.h
 create mode 100644 mcap/mcap_internal.h
 create mode 100644 mcap/mcap_lib.h

diff --git a/Makefile.am b/Makefile.am
index f4bf87d..d1e6b0e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -102,6 +102,7 @@ gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/object.c gdbus/watch.c
 builtin_modules =
 builtin_sources =
 builtin_nodist =
+mcap_sources =
 
 if PNATPLUGIN
 builtin_modules += pnat
@@ -168,6 +169,12 @@ builtin_modules += service
 builtin_sources += plugins/service.c
 endif
 
+if MCAP
+mcap_sources += mcap/mcap_internal.h	\
+		mcap/mcap_lib.h		\
+		mcap/mcap.h mcap/mcap.c
+endif
+
 builtin_modules += hciops
 builtin_sources += plugins/hciops.c
 
@@ -201,7 +208,8 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
 			src/adapter.h src/adapter.c \
 			src/device.h src/device.c \
 			src/dbus-common.c src/dbus-common.h \
-			src/dbus-hci.h src/dbus-hci.c
+			src/dbus-hci.h src/dbus-hci.c \
+			$(mcap_sources)
 src_bluetoothd_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @DBUS_LIBS@ \
 							@CAPNG_LIBS@ -ldl
 src_bluetoothd_LDFLAGS = -Wl,--export-dynamic \
@@ -323,6 +331,9 @@ AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@ \
 INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
 			-I$(srcdir)/audio -I$(srcdir)/sbc -I$(srcdir)/gdbus
 
+if MCAP
+INCLUDES += -I$(builddir)/mcap
+endif
 
 pkgconfigdir = $(libdir)/pkgconfig
 
diff --git a/acinclude.m4 b/acinclude.m4
index f5fdd66..db71da3 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -167,6 +167,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	serial_enable=yes
 	network_enable=yes
 	service_enable=yes
+	mcap_enable=no
 	pnat_enable=no
 	tracer_enable=no
 	tools_enable=yes
@@ -216,6 +217,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 		service_enable=${enableval}
 	])
 
+	AC_ARG_ENABLE(mcap, AC_HELP_STRING([--enable-mcap], [enable mcap support]), [
+			mcap_enable=${enableval}
+	])
+
 	AC_ARG_ENABLE(pnat, AC_HELP_STRING([--enable-pnat], [enable pnat plugin]), [
 		pnat_enable=${enableval}
 	])
@@ -330,6 +335,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
 	AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
 	AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
+	AM_CONDITIONAL(MCAP, test "${mcap_enable}" = "yes")
 	AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
 	AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
 	AM_CONDITIONAL(TRACER, test "${tracer_enable}" = "yes")
diff --git a/mcap/mcap.c b/mcap/mcap.c
new file mode 100644
index 0000000..8bd2ad2
--- /dev/null
+++ b/mcap/mcap.c
@@ -0,0 +1,54 @@
+/*
+ *
+ *  MCAP for BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  Authors:
+ *  Santiago Carot-Nemesio <sancane at gmail.com>
+ *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ *  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
+ *
+ */
+
+#include "log.h"
+#include "error.h"
+
+#include <netinet/in.h>
+
+#include "mcap.h"
+#include "mcap_lib.h"
+#include "mcap_internal.h"
+
+struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
+					BtIOSecLevel sec,
+					uint16_t ccpsm,
+					uint16_t dcpsm,
+					GError **gerr,
+					mcap_mcl_event_cb mcl_connected,
+					mcap_mcl_event_cb mcl_reconnected,
+					mcap_mcl_event_cb mcl_disconnected,
+					mcap_mcl_event_cb mcl_uncached,
+					gpointer user_data)
+{
+	/* TODO */
+	return NULL;
+}
+
+void mcap_release_instance(struct mcap_instance *ms)
+{
+	/* TODO */
+}
diff --git a/mcap/mcap.h b/mcap/mcap.h
new file mode 100644
index 0000000..0299f42
--- /dev/null
+++ b/mcap/mcap.h
@@ -0,0 +1,165 @@
+/*
+ *
+ *  MCAP for BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  Authors:
+ *  Santiago Carot-Nemesio <sancane at gmail.com>
+ *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ *  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
+ *
+ */
+
+#ifndef __MCAP_H
+#define __MCAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MCAP_VERSION	0x0100	/* current version 01.00 */
+
+/* bytes to get MCAP Supported Procedures */
+#define MCAP_SUP_PROC	0x06
+
+/* maximum transmission unit for channels */
+#define MCAP_CC_MTU	48
+#define MCAP_DC_MTU	L2CAP_DEFAULT_MTU
+
+
+/* MCAP Standard Op Codes */
+#define MCAP_ERROR_RSP			0x00
+#define MCAP_MD_CREATE_MDL_REQ		0x01
+#define MCAP_MD_CREATE_MDL_RSP		0x02
+#define MCAP_MD_RECONNECT_MDL_REQ	0x03
+#define MCAP_MD_RECONNECT_MDL_RSP	0x04
+#define MCAP_MD_ABORT_MDL_REQ		0x05
+#define MCAP_MD_ABORT_MDL_RSP		0x06
+#define MCAP_MD_DELETE_MDL_REQ		0x07
+#define MCAP_MD_DELETE_MDL_RSP		0x08
+
+/* MCAP Clock Sync Op Codes */
+#define MCAP_MD_SYNC_CAP_REQ		0x11
+#define MCAP_MD_SYNC_CAP_RSP		0x12
+#define MCAP_MD_SYNC_SET_REQ		0x13
+#define MCAP_MD_SYNC_SET_RSP            0x14
+#define MCAP_MD_SYNC_INFO_IND		0x15
+
+/* MCAP Response codes */
+#define MCAP_SUCCESS			0x00
+#define MCAP_INVALID_OP_CODE		0x01
+#define MCAP_INVALID_PARAM_VALUE	0x02
+#define MCAP_INVALID_MDEP		0x03
+#define MCAP_MDEP_BUSY			0x04
+#define MCAP_INVALID_MDL		0x05
+#define MCAP_MDL_BUSY			0x06
+#define MCAP_INVALID_OPERATION		0x07
+#define MCAP_RESOURCE_UNAVAILABLE	0x08
+#define MCAP_UNSPECIFIED_ERROR		0x09
+#define MCAP_REQUEST_NOT_SUPPORTED	0x0A
+#define MCAP_CONFIGURATION_REJECTED	0x0B
+
+/* MDL IDs */
+#define MCAP_MDLID_RESERVED		0x0000
+#define MCAP_MDLID_INITIAL		0x0001
+#define MCAP_MDLID_FINAL		0xFEFF
+#define MCAP_ALL_MDLIDS			0xFFFF
+
+/* MDEP IDs */
+#define MCAP_MDEPID_INITIAL		0x00
+#define MCAP_MDEPID_FINAL		0x7F
+
+
+/*
+ * MCAP Request Packet Format
+ */
+
+typedef struct {
+	uint8_t         op;
+        uint16_t	mdl;
+	uint8_t		mdep;
+	uint8_t		conf;
+} __attribute__ ((packed)) mcap_md_create_mdl_req;
+
+typedef struct {
+        uint8_t         op;
+        uint16_t        mdl;
+} __attribute__ ((packed)) mcap_md_req;
+
+
+/*
+ * MCAP Response Packet Format
+ */
+
+typedef struct {
+        uint8_t         op;
+        uint8_t         rc;
+	uint16_t        mdl;
+} __attribute__ ((packed)) mcap4B_rsp;
+
+typedef struct {
+        uint8_t         op;
+        uint8_t         rc;
+        uint16_t        mdl;
+        uint8_t         param;
+} __attribute__ ((packed)) mcap5B_rsp;
+
+
+/*
+ * MCAP Clock Synchronization Protocol
+ */
+typedef struct {
+        uint8_t         op;
+        uint16_t        timest;
+} __attribute__ ((packed)) mcap_md_sync_cap_req;
+
+typedef struct {
+        uint8_t         op;
+	uint8_t         rc;
+	uint8_t         btclock;
+        uint16_t        sltime;
+	uint16_t        timestnr;
+	uint16_t        timestna;
+} __attribute__ ((packed)) mcap_md_sync_cap_rsp;
+
+typedef struct {
+        uint8_t         op;
+	uint8_t         timestui;
+        uint32_t        btclock;
+	uint64_t        timestst;
+} __attribute__ ((packed)) mcap_md_sync_set_req;
+
+typedef struct {
+        uint8_t         op;
+	uint8_t         rc;
+        uint32_t        btclock;
+	uint64_t        timestst;
+	uint16_t        timestsa;
+} __attribute__ ((packed)) mcap_md_sync_set_rsp;
+
+typedef struct {
+        uint8_t         op;
+        uint32_t        btclock;
+	uint64_t        timestst;
+	uint16_t        timestsa;
+} __attribute__ ((packed)) mcap_md_sync_info_ind;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MCAP_H */
diff --git a/mcap/mcap_internal.h b/mcap/mcap_internal.h
new file mode 100644
index 0000000..3aaeed5
--- /dev/null
+++ b/mcap/mcap_internal.h
@@ -0,0 +1,118 @@
+/*
+ *
+ *  MCAP for BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  Authors:
+ *  Santiago Carot-Nemesio <sancane at gmail.com>
+ *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ *  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
+ *
+ */
+
+#ifndef __MCAP_INTERNAL_H
+#define __MCAP_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+	MCL_CONNECTED,
+	MCL_PENDING,
+	MCL_ACTIVE,
+	MCL_IDLE
+} MCLState;
+
+typedef enum {
+	MCL_ACCEPTOR,
+	MCL_INITIATOR
+} MCLRole;
+
+typedef enum {
+	MCL_AVAILABLE,
+	MCL_WAITING_RSP
+} MCAPCtrl;
+
+typedef enum {
+	MDL_WAITING,
+	MDL_CONNECTED,
+	MDL_DELETING,
+	MDL_CLOSED
+} MDLState;
+
+struct mcap_mdl_cb {
+	mcap_mdl_event_cb 		mdl_connected;	/* Remote device has created a MDL */
+	mcap_mdl_event_cb 		mdl_closed;	/* Remote device has closed a MDL */
+	mcap_mdl_event_cb 		mdl_deleted;	/* Remote device requested deleting a MDL */
+	mcap_mdl_event_cb		mdl_aborted;	/* Remote device aborted the mdl creation */
+	mcap_remote_mdl_conn_req_cb	mdl_conn_req;	/* Remote device requested creating a MDL */
+	mcap_remote_mdl_reconn_req_cb 	mdl_reconn_req;	/* Remote device requested reconnecting a MDL */
+	gpointer			user_data;	/* User data */
+};
+
+struct mcap_instance {
+	bdaddr_t		src;			/* Source address */
+	GIOChannel		*ccio;			/* Control Channel IO */
+	GIOChannel		*dcio;			/* Data Channel IO */
+	GSList			*mcls;			/* MCAP instance list */
+	GSList			*cached;		/* List with all cached MCLs (MAX_CACHED macro) */
+	BtIOSecLevel		sec;			/* Security level */
+	mcap_mcl_event_cb	mcl_connected_cb;	/* New MCL connected */
+	mcap_mcl_event_cb	mcl_reconnected_cb;	/* Old MCL has been reconnected */
+	mcap_mcl_event_cb	mcl_disconnected_cb;	/* MCL disconnected */
+	mcap_mcl_event_cb	mcl_uncached_cb;	/* MCL has been removed from MCAP cache */
+	gpointer		user_data;		/* Data to be provided in callbacks */
+};
+
+struct mcap_mcl {
+	struct mcap_instance	*ms;		/* MCAP instance where this MCL belongs */
+	bdaddr_t		addr;		/* Device address */
+	GIOChannel		*cc;		/* MCAP Control Channel IO */
+	guint			wid;		/* MCL Watcher id */
+	GSList			*mdls;		/* List of Data Channels shorted by mdlid */
+	MCLState		state;		/* Current MCL State */
+	MCLRole			role;		/* Initiator or acceptor of this MCL */
+	MCAPCtrl		req;		/* Request control flag */
+	void			*priv_data;	/* Temporal data to manage in responses */
+	struct mcap_mdl_cb	*cb;		/* MDL callbacks */
+	guint			tid;		/* Timer id for waiting for a response */
+	uint8_t			*lcmd;		/* Last command sent */
+	guint			ref;		/* References counter */
+	uint8_t			ctrl;		/* MCL control flag */
+};
+
+#define	MCAP_CTRL_CACHED	0x01	/* MCL is cached */
+#define	MCAP_CTRL_STD_OP	0x02	/* Support for standard op codes */
+#define	MCAP_CTRL_SYNC_OP	0x04	/* Support for synchronization commands */
+#define	MCAP_CTRL_CONN		0x08	/* MCL is in connecting process */
+#define	MCAP_CTRL_FREE		0x10	/* MCL is marked as releasable */
+#define	MCAP_CTRL_NOCACHE	0x20	/* MCL is marked as not cacheable */
+
+struct mcap_mdl {
+	struct mcap_mcl		*mcl;		/* MCL where this MDL belongs */
+	GIOChannel		*dc;		/* MCAP Data Channel IO */
+	guint			wid;		/* MDL Watcher id */
+	uint16_t		mdlid;		/* MDL id */
+	uint8_t			mdep_id;	/* MCAP Data End Point */
+	MDLState		state;		/* MDL state */
+};
+
+int mcap_send_data(int sock, const uint8_t *buf, uint32_t size);
+void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len);
+
+#endif /* __MCAP_INTERNAL_H */
diff --git a/mcap/mcap_lib.h b/mcap/mcap_lib.h
new file mode 100644
index 0000000..2283dac
--- /dev/null
+++ b/mcap/mcap_lib.h
@@ -0,0 +1,161 @@
+/*
+ *
+ *  MCAP for BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  Authors:
+ *  Santiago Carot-Nemesio <sancane at gmail.com>
+ *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
+ *
+ *  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
+ *
+ */
+
+#ifndef __MCAP_LIB_H
+#define __MCAP_LIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "adapter.h"
+#include "btio.h"
+#include <bluetooth/l2cap.h>
+
+typedef enum {
+/* MCAP Error Response Codes */
+	MCAP_ERROR_INVALID_OP_CODE = 1,
+	MCAP_ERROR_INVALID_PARAM_VALUE,
+	MCAP_ERROR_INVALID_MDEP,
+	MCAP_ERROR_MDEP_BUSY,
+	MCAP_ERROR_INVALID_MDL,
+	MCAP_ERROR_MDL_BUSY,
+	MCAP_ERROR_INVALID_OPERATION,
+	MCAP_ERROR_RESOURCE_UNAVAILABLE,
+	MCAP_ERROR_UNSPECIFIED_ERROR,
+	MCAP_ERROR_REQUEST_NOT_SUPPORTED,
+	MCAP_ERROR_CONFIGURATION_REJECTED,
+/* MCAP Internal Errors */
+	MCAP_ERROR_INVALID_ARGS,
+	MCAP_ERROR_ALREADY_EXISTS,
+	MCAP_ERROR_FAILED
+} McapError;
+
+typedef enum {
+	MCAP_MDL_CB_INVALID,
+	MCAP_MDL_CB_CONNECTED,		/* mcap_mdl_event_cb */
+	MCAP_MDL_CB_CLOSED,		/* mcap_mdl_event_cb */
+	MCAP_MDL_CB_DELETED,		/* mcap_mdl_event_cb */
+	MCAP_MDL_CB_ABORTED,		/* mcap_mdl_event_cb */
+	MCAP_MDL_CB_REMOTE_CONN_REQ,	/* mcap_remote_mdl_conn_req_cb */
+	MCAP_MDL_CB_REMOTE_RECONN_REQ	/* mcap_remote_mdl_reconn_req_cb */
+} McapMclCb;
+
+struct mcap_instance;
+struct mcap_mcl;
+struct mcap_mdl;
+
+/************ Callbacks ************/
+
+/* mdl callbacks */
+
+typedef void (* mcap_mdl_event_cb) (struct mcap_mdl *mdl, gpointer data);
+typedef void (* mcap_mdl_operation_conf_cb) (struct mcap_mdl *mdl, uint8_t conf,
+						GError *err, gpointer data);
+typedef void (* mcap_mdl_operation_cb) (struct mcap_mdl *mdl, GError *err,
+						gpointer data);
+typedef void (* mcap_mdl_del_cb) (GError *err, gpointer data);
+
+/* Next function should return an MCAP appropriate response code */
+typedef uint8_t (* mcap_remote_mdl_conn_req_cb) (struct mcap_mcl *mcl,
+						uint8_t mdepid, uint16_t mdlid,
+						uint8_t *conf, gpointer data);
+typedef uint8_t (* mcap_remote_mdl_reconn_req_cb) (struct mcap_mdl *mdl,
+						gpointer data);
+
+/* mcl callbacks */
+
+typedef void (* mcap_mcl_event_cb) (struct mcap_mcl *mcl, gpointer data);
+typedef void (* mcap_mcl_connect_cb) (struct mcap_mcl *mcl, GError *err,
+								gpointer data);
+
+/************ Operations ************/
+
+/* Mdl operations*/
+
+void mcap_req_mdl_creation(struct mcap_mcl *mcl,
+				uint8_t mdepid,
+				uint8_t conf,
+				GError **err,
+				mcap_mdl_operation_conf_cb connect_cb,
+				gpointer user_data);
+void mcap_req_mdl_reconnect(struct mcap_mdl *mdl, GError **err,
+				mcap_mdl_operation_cb reconnect_cb,
+				gpointer user_data);
+void mcap_req_mdl_delete_all(struct mcap_mcl *mcl, GError **err,
+			mcap_mdl_del_cb delete_cb, gpointer user_data);
+void mcap_req_mdl_deletion(struct mcap_mdl *mdl, GError **err,
+			mcap_mdl_del_cb delete_cb, gpointer user_data);
+void mcap_mdl_connect(struct mcap_mdl *mdl,
+			BtIOType BtType,
+			uint16_t dcpsm,
+			GError **err,
+			mcap_mdl_operation_cb connect_cb,
+			gpointer user_data);
+void mcap_mdl_abort(struct mcap_mdl *mdl, GError **err,
+			mcap_mdl_del_cb abort_cb, gpointer user_data);
+
+int mcap_mdl_get_fd(struct mcap_mdl *mdl);
+uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl);
+
+/* Mcl operations*/
+
+void mcap_create_mcl(struct mcap_instance *ms,
+				const bdaddr_t *addr,
+				uint16_t ccpsm,
+				GError **err,
+				mcap_mcl_connect_cb connect_cb,
+				gpointer user_data);
+void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache);
+void mcap_mcl_set_cb(struct mcap_mcl *mcl, GError **gerr,
+					gpointer user_data, McapMclCb cb1, ...);
+bdaddr_t mcap_mcl_get_addr(struct mcap_mcl *mcl);
+
+struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl);
+void mcap_mcl_unref(struct mcap_mcl *mcl);
+
+/* MCAP main operations */
+
+struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter,
+					BtIOSecLevel sec, uint16_t ccpsm,
+					uint16_t dcpsm,
+					GError **gerr,
+					mcap_mcl_event_cb mcl_connected,
+					mcap_mcl_event_cb mcl_reconnected,
+					mcap_mcl_event_cb mcl_disconnected,
+					mcap_mcl_event_cb mcl_uncached,
+					gpointer user_data);
+
+void mcap_release_instance(struct mcap_instance *ms);
+
+uint16_t mcap_get_ctrl_psm(struct mcap_instance *ms, GError **err);
+uint16_t mcap_get_data_psm(struct mcap_instance *ms, GError **err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MCAP_LIB_H */
-- 
1.6.3.3


^ permalink raw reply related

* MCAP Patches
From: Santiago Carot-Nemesio @ 2010-07-22  8:51 UTC (permalink / raw)
  To: linux-bluetooth

Hello,

Next you are MCAP patches that José Antonio Santos Cadenas and me have generated for BlueZ.
We still believe that MCAP should be an independent library from HDP because other profiles
non health related may want to use it in the future, if we set this health dependency we will
force to import health features in plugins that only require MCAP.
Nevertheless, as we accorded last week in Brazil we are sending a last patch to set MCAP
into health directory with HDP. We leave in your hands upload it as health plugin or not.

Regards



^ permalink raw reply

* Re: [PATCH] systemd: install systemd unit files
From: Johan Hedberg @ 2010-07-22  7:28 UTC (permalink / raw)
  To: Lennart Poettering; +Cc: marcel, linux-bluetooth
In-Reply-To: <20100721220828.GA7799@tango.0pointer.de>

Hi Lennart,

On Thu, Jul 22, 2010, Lennart Poettering wrote:
> This also enables bus activation for bluetoothd, but only if systemd is
> running. Only if that's the case we can make sure in a race-free fashion
> that bluetoothd is not started twice at the same time.
> ---
>  Makefile.am                  |   21 ++++++++++++++++++---
>  configure.ac                 |    9 +++++++++
>  scripts/.gitignore           |    1 +
>  scripts/bluetooth.service.in |   12 ++++++++++++
>  scripts/org.bluez.service    |    5 +++++
>  5 files changed, 45 insertions(+), 3 deletions(-)
>  create mode 100644 scripts/.gitignore
>  create mode 100644 scripts/bluetooth.service.in
>  create mode 100644 scripts/org.bluez.service

Looks fine to me, but I'll let Marcel handle pushing it upstream since
he had issues with the previous version (on IRC) that I didn't see
myself.

Johan

^ permalink raw reply

* [PATCH] systemd: install systemd unit files
From: Lennart Poettering @ 2010-07-21 22:08 UTC (permalink / raw)
  To: marcel, linux-bluetooth

This also enables bus activation for bluetoothd, but only if systemd is
running. Only if that's the case we can make sure in a race-free fashion
that bluetoothd is not started twice at the same time.
---
 Makefile.am                  |   21 ++++++++++++++++++---
 configure.ac                 |    9 +++++++++
 scripts/.gitignore           |    1 +
 scripts/bluetooth.service.in |   12 ++++++++++++
 scripts/org.bluez.service    |    5 +++++
 5 files changed, 45 insertions(+), 3 deletions(-)
 create mode 100644 scripts/.gitignore
 create mode 100644 scripts/bluetooth.service.in
 create mode 100644 scripts/org.bluez.service

diff --git a/Makefile.am b/Makefile.am
index 65d4312..a2b53e8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -301,7 +301,8 @@ endif
 CLEANFILES += $(rules_DATA)
 
 EXTRA_DIST += scripts/bluetooth.rules \
-		scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules
+		scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules \
+		scripts/bluetooth.service.in scripts/org.bluez.service
 
 if PCMCIA
 udevdir = $(libexecdir)/udev
@@ -309,6 +310,20 @@ udevdir = $(libexecdir)/udev
 dist_udev_SCRIPTS = scripts/bluetooth_serial
 endif
 
+if HAVE_SYSTEMD
+systemdsystemunit_DATA = \
+       scripts/bluetooth.service
+
+scripts/bluetooth.service: scripts/bluetooth.service.in
+	@$(SED) -e "s|\@sbindir\@|$(sbindir)|" $< >$@
+
+dbussystemservicesdir = $(datadir)/dbus-1/system-services
+
+dbussystemservices_DATA = \
+	scripts/org.bluez.service
+
+endif
+
 EXTRA_DIST += doc/manager-api.txt \
 		doc/adapter-api.txt doc/device-api.txt \
 		doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \
@@ -328,9 +343,9 @@ pkgconfigdir = $(libdir)/pkgconfig
 
 pkgconfig_DATA = bluez.pc
 
-DISTCHECK_CONFIGURE_FLAGS = --disable-udevrules
+DISTCHECK_CONFIGURE_FLAGS = --disable-udevrules --with-systemdsystemunitdir=
 
-DISTCLEANFILES = $(pkgconfig_DATA)
+DISTCLEANFILES = $(pkgconfig_DATA) scripts/bluetooth.service
 
 MAINTAINERCLEANFILES = Makefile.in \
 	aclocal.m4 configure config.h.in config.sub config.guess \
diff --git a/configure.ac b/configure.ac
index b004f6e..86b398f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -64,5 +64,14 @@ if (test "${enable_netlink}" = "yes"); then
 fi
 AM_CONDITIONAL(NETLINK, test "${enable_netlink}" = "yes")
 
+# systemd
+
+AC_ARG_WITH([systemdsystemunitdir],
+        AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
+        [],
+        [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
+AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
+AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir"])
+
 AC_OUTPUT(Makefile scripts/bluetooth.rules doc/version.xml
 					src/bluetoothd.8 bluez.pc)
diff --git a/scripts/.gitignore b/scripts/.gitignore
new file mode 100644
index 0000000..4b9f765
--- /dev/null
+++ b/scripts/.gitignore
@@ -0,0 +1 @@
+bluetooth.service
diff --git a/scripts/bluetooth.service.in b/scripts/bluetooth.service.in
new file mode 100644
index 0000000..f95b0b0
--- /dev/null
+++ b/scripts/bluetooth.service.in
@@ -0,0 +1,12 @@
+[Unit]
+Description=Bluetooth Manager
+After=syslog.target
+
+[Service]
+Type=dbus
+BusName=org.bluez
+ExecStart=@sbindir@/bluetoothd -n
+StandardOutput=syslog
+
+[Install]
+WantedBy=bluetooth.target
diff --git a/scripts/org.bluez.service b/scripts/org.bluez.service
new file mode 100644
index 0000000..2a3b057
--- /dev/null
+++ b/scripts/org.bluez.service
@@ -0,0 +1,5 @@
+[D-BUS Service]
+Name=org.bluez
+Exec=/bin/false
+User=root
+SystemdService=bluetooth.service
-- 
1.7.0.1



Lennart

-- 
Lennart Poettering - Red Hat, Inc.

^ permalink raw reply related

* Re: Any update on software caused connection abort issue??
From: Lukas @ 2010-07-21 15:53 UTC (permalink / raw)
  To: john michelle; +Cc: linux-bluetooth
In-Reply-To: <AANLkTilPI6nA-9SJJx74L1wEIMci7IZ7K_bnGAT2YYTT@mail.gmail.com>

Hello,

On Wednesday 21 July 2010 17:35:15 john michelle wrote:
> Any update on software caused connection abort issue

I also noticed this error when I used the software suite Series60-Remote to 
connect to my mobile phone.

Shortly after the connection establishment is completed I get the error 
message "software caused connection abort" and the device gets disconnected.

I also see the HCI reset, as described below, when I try to investigate this 
error using hcidump.

The software uses the RFCOMM protocol for the connection.
I use an USB bluetooth adapter from Belkin, lsusb reports the following device 
id:
ID 050d:0131 Belkin Components Bluetooth Device with trace filter

This bug happens with the following kernel:
root@erde ~  #  rpm -q kernel bluez
kernel-2.6.33.6-147.fc13.x86_64
bluez-4.64-1.fc13.x86_64

You can also look at this thread in my mailing list for further informations: 
https://sourceforge.net/mailarchive/forum.php?thread_name=201007192136.27723.LuHe%40gmx.at&forum_name=series60-
remote-devel

It would be great to see this problem fixed soon, because it's nearly 
impossible to use bluetooth on my PC.

Thanks,
Lukas

> >>On Wed, Jun 23, 2010 at 12:48 AM, john michelle <jhnmichelle@gmail.com> 
wrote:
> >> Dear Bluetooth community,
> >> 
> >> You are committing version after version and have time to add new
> >> Features and the core stack have a major bug (software Caused
> >> connection abort) that i
> >> Have reported on the 7th of may the problem seems to be either in the
> >> usb part of the
> >> Kernel or the bluez stack, i am no kernel engineer so i came directly
> >> to you for reporting
> >> This problem and my requests to look into this problem are just
> >> ignored. this is a blocker
> >> Issue that would prevent and discourage any one from developing
> >> application that rely on
> >> Bluez sco capabilities, since during transmission the above mentioned
> >> error just occurs.
> >> I hope that my voice is heared and i would get a reply from the bluez
> >> community.
> >> 
> >> John
> >> 
> >> On Wed, Jun 16, 2010 at 3:11 PM, john michelle <jhnmichelle@gmail.com> 
wrote:
> >>> On Sun, May 30, 2010 at 1:12 PM, john michelle <jhnmichelle@gmail.com> 
wrote:
> >>>> Hi Gustavo,
> >>>> 
> >>>>>> Please post the output of hcidump when the connection abort happens.
> >>>> 
> >>>> Below is the output of hcidump the moments the software caused
> >>>> connection abort
> >>>> 
> >>>> Dongle 1:
> >>>>> HCI Event: Number of Completed Packets (0x13) plen 5
> >>>> 
> >>>>  . * . . .
> >>>> < HCI Command: Reset (0x03|0x0003) plen 0
> >>>> device: disconnected
> >>>> 
> >>>> Dongle 2:
> >>>>> HCI Event: Number of Completed Packets (0x13) plen 5
> >>>> 
> >>>>  . * . . .
> >>>> < HCI Command: Reset (0x03|0x0003) plen 0
> >>>> device: disconnected
> >>>> 
> >>>> 
> >>>> I think something triggers hci reset which causes this problem, but
> >>>> what exactly Triggers it i don't know.
> >>>> 
> >>>> 
> >>>> John
> >>> 
> >>> Hi all,
> >>> 
> >>> Is anyone going to give this problem a try, it has been like a month
> >>> now This is a real problem in the bluez stack and someone have to look
> >>> in this Issue.
> >>> 
> >>> John
> >>> 
> >>>> On Mon, May 17, 2010 at 5:21 PM, john michelle <jhnmichelle@gmail.com> 
wrote:
> >>>>>> Hi Jonh,
> >>>>>> 
> >>>>>> First of all, don't do top posting in this mailing list. ;)
> >>>>> 
> >>>>> Thanks for the advise , will keep that in mind for future posts.
> >>>>> 
> >>>>>> In which bluez/kernel version the problem started? Any hardware
> >>>>>> update during this time? The problem happens when you are already
> >>>>>> tranfering SCO data?
> >>>>> 
> >>>>> I tried bluez versions 3.XX  and kernel 2.6.26(I think) the problem
> >>>>> occurs and the kernel panics with no core dumps.then i tried with
> >>>>> bluez 4.53-4.62 with
> >>>>> Kernel 2.6.31 and 2.6.32. the connection abort problem occurs but the
> >>>>> kernel doesn't
> >>>>> Panic. regarding the hardware update you mean the dongle or the
> >>>>> box.Anyway i changed both and tried different box's, this even
> >>>>> happens on a box with 2 giga ram
> >>>>> And core2 processor . as for the dongles i am using trust
> >>>>> 
> >>>>> http://www.twenga.co.uk/prices-Bluetooth-2-USB-Adapter-10m-BT-2250p-T
> >>>>> RUST-Wireless-network-card-adapter-176178-0
> >>>>> 
> >>>>>  and also using no name dongles all the same problem.
> >>>>> 
> >>>>>> Please post the output of hcidump when the connection abort happens.
> >>>>> 
> >>>>> well that is going to be a hard one since i have more than one dongle
> >>>>> in place And very hard to predict which one will crash.i will work
> >>>>> on this and update You as soon as i have the hcidump log.
> >>>>> 
> >>>>>> I tried reproduce this issue in L2CAP but it is a bit hard, lets
> >>>>>> say it happen once in a thousand, so it's not easy to track it. I
> >>>>>> have to try reproduce that using the SCO, but I'm not used to that
> >>>>>> layer yet. ;)
> >>>>> 
> >>>>> I hoped that it happens 1 in 1000 in SCO , but it actually happens 1
> >>>>> in 15
> >>>>> 
> >>>>> 
> >>>>> John
> >>>>> 
> >>>>>> Regards,
> >>>>>> 
> >>>>>>> John
> >>>>>>> 
> >>>>>>> On Fri, May 7, 2010 at 3:53 PM, Gustavo F. Padovan 
<gustavo@padovan.org> wrote:
> >>>>>>> > * john michelle <jhnmichelle@gmail.com> [2010-05-07 15:49:05 
-0400]:
> >>>>>>> >> Hi Bluetooth hackers,
> >>>>>>> >> 
> >>>>>>> >> i am having this consistent problem with bluez , from time to
> >>>>>>> >> time i get the error Software caused connection abort (103 )
> >>>>>>> >> And the bluetooth stick seems to disconnect and reconnects. this
> >>>>>>> >> happens during an sco connection and it occurs even
> >>>>>>> >> More when i am having the voice stream comming through the
> >>>>>>> >> internet rather than the lan.i don't know what exact
> >>>>>>> >> Details you need to solve this problem please tell me and i will
> >>>>>>> >> give you an immediate reply . i have linux kernel 2.6.33 and
> >>>>>>> >> bluez 4.62
> >>>>>>> > 
> >>>>>>> > I get the same problem sometimes when testing ERTM with l2test.
> >>>>>>> > So the problem is on l2cap too. I didn't have time to debug this
> >>>>>>> > yet. Now that someone else have confirmed it too, I'll to take a
> >>>>>>> > look at the problem.
> >>>>>> 
> >>>>>> --
> >>>>>> Gustavo F. Padovan
> >>>>>> http://padovan.org
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth"
> in the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: Any update on software caused connection abort issue??
From: john michelle @ 2010-07-21 15:35 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <AANLkTikxtNwbaiSRouqTwB1o7y4hFTRXJ_mejsBFeYKM@mail.gmail.com>

Any update on software caused connection abort issue
>
>
>
>>On Wed, Jun 23, 2010 at 12:48 AM, john michelle <jhnmichelle@gmail.com> wrote:
>> Dear Bluetooth community,
>>
>> You are committing version after version and have time to add new
>> Features and the core stack have a major bug (software Caused
>> connection abort) that i
>> Have reported on the 7th of may the problem seems to be either in the
>> usb part of the
>> Kernel or the bluez stack, i am no kernel engineer so i came directly
>> to you for reporting
>> This problem and my requests to look into this problem are just
>> ignored. this is a blocker
>> Issue that would prevent and discourage any one from developing
>> application that rely on
>> Bluez sco capabilities, since during transmission the above mentioned
>> error just occurs.
>> I hope that my voice is heared and i would get a reply from the bluez community.
>>
>> John
>>
>>
>>
>> On Wed, Jun 16, 2010 at 3:11 PM, john michelle <jhnmichelle@gmail.com> wrote:
>>> On Sun, May 30, 2010 at 1:12 PM, john michelle <jhnmichelle@gmail.com> wrote:
>>>> Hi Gustavo,
>>>>
>>>>>> Please post the output of hcidump when the connection abort happens.
>>>>>>
>>>>
>>>> Below is the output of hcidump the moments the software caused connection abort
>>>>
>>>> Dongle 1:
>>>>> HCI Event: Number of Completed Packets (0x13) plen 5
>>>>  . * . . .
>>>> < HCI Command: Reset (0x03|0x0003) plen 0
>>>> device: disconnected
>>>>
>>>> Dongle 2:
>>>>> HCI Event: Number of Completed Packets (0x13) plen 5
>>>>  . * . . .
>>>> < HCI Command: Reset (0x03|0x0003) plen 0
>>>> device: disconnected
>>>>
>>>>
>>>> I think something triggers hci reset which causes this problem, but what exactly
>>>> Triggers it i don't know.
>>>>
>>>>
>>>> John
>>>>
>>>>
>>>
>>>
>>> Hi all,
>>>
>>> Is anyone going to give this problem a try, it has been like a month now
>>> This is a real problem in the bluez stack and someone have to look in this
>>> Issue.
>>>
>>> John
>>>
>>>> On Mon, May 17, 2010 at 5:21 PM, john michelle <jhnmichelle@gmail.com> wrote:
>>>>>> Hi Jonh,
>>>>>>
>>>>>> First of all, don't do top posting in this mailing list. ;)
>>>>>>
>>>>>
>>>>> Thanks for the advise , will keep that in mind for future posts.
>>>>>
>>>>>> In which bluez/kernel version the problem started? Any hardware update
>>>>>> during this time? The problem happens when you are already tranfering
>>>>>> SCO data?
>>>>>>
>>>>>
>>>>> I tried bluez versions 3.XX  and kernel 2.6.26(I think) the problem
>>>>> occurs and the kernel panics with no core dumps.then i tried with
>>>>> bluez 4.53-4.62 with
>>>>> Kernel 2.6.31 and 2.6.32. the connection abort problem occurs but the
>>>>> kernel doesn't
>>>>> Panic. regarding the hardware update you mean the dongle or the box.Anyway
>>>>> i changed both and tried different box's, this even happens on a box
>>>>> with 2 giga ram
>>>>> And core2 processor . as for the dongles i am using trust
>>>>>
>>>>> http://www.twenga.co.uk/prices-Bluetooth-2-USB-Adapter-10m-BT-2250p-TRUST-Wireless-network-card-adapter-176178-0
>>>>>
>>>>>  and also using no name dongles all the same problem.
>>>>>
>>>>>> Please post the output of hcidump when the connection abort happens.
>>>>>>
>>>>>
>>>>> well that is going to be a hard one since i have more than one dongle in place
>>>>> And very hard to predict which one will crash.i will work on this and update
>>>>> You as soon as i have the hcidump log.
>>>>>
>>>>>
>>>>>
>>>>>> I tried reproduce this issue in L2CAP but it is a bit hard, lets
>>>>>> say it happen once in a thousand, so it's not easy to track it. I have
>>>>>> to try reproduce that using the SCO, but I'm not used to that layer yet.
>>>>>> ;)
>>>>>
>>>>> I hoped that it happens 1 in 1000 in SCO , but it actually happens 1 in 15
>>>>>
>>>>>
>>>>> John
>>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> Regards,
>>>>>>
>>>>>>>
>>>>>>> John
>>>>>>>
>>>>>>> On Fri, May 7, 2010 at 3:53 PM, Gustavo F. Padovan <gustavo@padovan.org> wrote:
>>>>>>> > * john michelle <jhnmichelle@gmail.com> [2010-05-07 15:49:05 -0400]:
>>>>>>> >
>>>>>>> >> Hi Bluetooth hackers,
>>>>>>> >>
>>>>>>> >> i am having this consistent problem with bluez , from time to time i
>>>>>>> >> get the error Software caused connection abort (103 )
>>>>>>> >> And the bluetooth stick seems to disconnect and reconnects. this
>>>>>>> >> happens during an sco connection and it occurs even
>>>>>>> >> More when i am having the voice stream comming through the internet
>>>>>>> >> rather than the lan.i don't know what exact
>>>>>>> >> Details you need to solve this problem please tell me and i will give
>>>>>>> >> you an immediate reply . i have linux kernel 2.6.33 and bluez 4.62
>>>>>>> >
>>>>>>> > I get the same problem sometimes when testing ERTM with l2test. So the
>>>>>>> > problem is on l2cap too. I didn't have time to debug this yet. Now that
>>>>>>> > someone else have confirmed it too, I'll to take a look at the problem.
>>>>>>> >
>>>>>>> >>
>>>>>>
>>>>>> --
>>>>>> Gustavo F. Padovan
>>>>>> http://padovan.org
>>>>>>
>>>>>
>>>>
>>>
>>
>

^ permalink raw reply

* Re: [PATCH][RFC] Fix SDP resolving segfault
From: Manuel Naranjo @ 2010-07-21 15:15 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: BlueZ
In-Reply-To: <AANLkTikcy_R0SOhL52AD372_DTA3c2pUVEY85lh3ZEj3@mail.gmail.com>

Luiz,
>> I don't really understand the need for these changes, but admitedly the
>> function does have issues since it first checks for !ctxt->session and
>> then later for ctxt->session even though at that point it's already
>> guaranteed that ctxt->session is not NULL.
>>      
> Yep, I suspect it is something else too, there doesn't seems to be a
> call to bt_cancel_discovery in the last trace sent to the list, but
> the check for ctxt->session there seems buggy, we should always remove
> the context doesn't matter if it is connected or not.
>    
I think the problem is that the watch function is still registered even 
though we no longer have a session... maybe this doesn't make sense, no 
way we have a context and don't have a session.

Still if there's no session the context never gets released.

> @Manuel: Does valgrind give you a nice bracktrace when it bluetoothd segfaults?
>
> Normally I use something like this:
>
>    
>> sudo valgrind --trace-children=yes ./bluetoothd -dn
>>      
Check the other email, I made it by running bluetoothd -ndt (this is a 
feature I commited, which uses instrumentation-functions from gcc, a 
really nice feature).

Manuel


^ permalink raw reply

* Re: [PATCH][RFC] Fix SDP resolving segfault
From: Manuel Naranjo @ 2010-07-21 15:11 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: BlueZ
In-Reply-To: <20100721101934.GA12188@jh-x301>

Johan,
> Thanks for the patch proposal. It seems like you're trying to to fix the
> issue by doing all sorts of minor tweaks here and there, i.e. it seems
> like there isn't a full understanding of the real root cause.
>
I agree, I know this doesn't fix the root cause, it only works it out. 
Like we say in Argentina we attach it with aluminium threads.
>> -	if (ctxt->cb)
>> +	if (ctxt->cb&&  ctxt->user_data)
>>   		ctxt->cb(recs, err, ctxt->user_data);
>>
> This part isn't right. It should be perfectly fine for a discovery
> requester to pass NULL as user_data and still expect its callback to get
> called.
>
Then the problem is the callback function!

The trace shows that browse_cb gets right into search_cb which never 
checks if user_data is NULL. It doesn't do it because MOST of the time 
it isn't only when something weird happens.

>> -		if (ctxt->cb)
>> +		if (ctxt->cb&&  ctxt->user_data)
>>   			ctxt->cb(NULL, err, ctxt->user_data);
>>
> Same here.
>
>
>> @@ -254,6 +256,8 @@ static gboolean connect_watch(GIOChannel *chan, GIOCondition cond, gpointer user
>>   	int sk, err = 0;
>>
>>   	sk = g_io_channel_unix_get_fd(chan);
>> +	if (ctxt->io_id)
>> +	    g_source_remove(ctxt->io_id);
>>
> connect_watch returns FALSE in all cases which will remove the GSource.
> So the change you're doing seems redundant.
>
Ok you got me I missed that.


>> @@ -391,11 +395,13 @@ int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst)
>>   		return -ENODATA;
>>
>>   	ctxt = match->data;
>> -	if (!ctxt->session)
>> -		return -ENOTCONN;
>>
>>   	if (ctxt->io_id)
>>   		g_source_remove(ctxt->io_id);
>> +	ctxt->io_id = 0;
>> +
>> +	if (!ctxt->session)
>> +		return -ENOTCONN;
>>
>>   	if (ctxt->session)
>>   		sdp_close(ctxt->session);
>>
> I don't really understand the need for these changes, but admitedly the
> function does have issues since it first checks for !ctxt->session and
> then later for ctxt->session even though at that point it's already
> guaranteed that ctxt->session is not NULL.
>
I think this is the one that really fix the problem. I see connect_watch 
getting called and then getting into the crash. I have a nice log with 
the tracing feature I sent the other day, here's the end of it (the hole 
thing is almost 40 megs if someone wants just ask for it).


         +  0 0x808a019 (from 0x17fdab)  io_security_event()
         +  1 0x8087c29 (from 0x808a121)   hci_test_bit()
         +  1 0x80893be (from 0x808a166)   cmd_status()
         +  1 0x808812b (from 0x808a38a)   check_pending_hci_req()
         +  0 0x808a019 (from 0x17fdab)  io_security_event()
         +  1 0x8087c29 (from 0x808a121)   hci_test_bit()
         +  1 0x8089425 (from 0x808a187)   cmd_complete()
         +  1 0x808812b (from 0x808a38a)   check_pending_hci_req()
         +  0 0x808a019 (from 0x17fdab)  io_security_event()
         +  1 0x8087c29 (from 0x808a121)   hci_test_bit()
         +  1 0x8089b72 (from 0x808a2f4)   conn_complete()
         +  2 0x80add52 (from 0x8089bda)    hcid_dbus_conn_complete()
         +  3 0x80ac3e0 (from 0x80adda1)     get_adapter_and_device()
         +  4 0x809d9c3 (from 0x80ac405)      manager_find_adapter()
         +  5 0x809d8e3 (from 0x16847e)       adapter_cmp()
         +  6 0x80a44f7 (from 0x809d91b)        adapter_get_address()
         +  7 0x809dff1 (from 0x80a4525)         bacpy()
         +  6 0x809cf7c (from 0x809d92d)        bacmp()
         +  4 0x80a0aba (from 0x80ac45b)      adapter_get_device()
         +  5 0x8087840 (from 0x80a0b03)       btd_debug()
         +  5 0x80a041a (from 0x80a0b22)       adapter_find_device()
         +  6 0x80a883e (from 0x16847e)        device_address_cmp()
....
         +  6 0x80a883e (from 0x16847e)        device_address_cmp()
         +  3 0x80a80a3 (from 0x80addc4)     device_get_secmode3_conn()
         +  3 0x80a80e1 (from 0x80addda)     device_set_secmode3_conn()
         +  3 0x80aaddf (from 0x80added)     device_is_bonding()
         +  3 0x80a9cf7 (from 0x80ade0f)     device_is_temporary()
         +  1 0x808812b (from 0x808a38a)   check_pending_hci_req()
         +  0 0x808a019 (from 0x17fdab)  io_security_event()
         +  1 0x8087c29 (from 0x808a121)   hci_test_bit()
         +  1 0x80891f0 (from 0x808a239)   inquiry_complete()
         +  2 0x809d9c3 (from 0x808923f)    manager_find_adapter()
         +  3 0x809d8e3 (from 0x16847e)     adapter_cmp()
         +  4 0x80a44f7 (from 0x809d91b)      adapter_get_address()
         +  5 0x809dff1 (from 0x80a4525)       bacpy()
         +  4 0x809cf7c (from 0x809d92d)      bacmp()
         +  2 0x809e7a5 (from 0x808929a)    adapter_resolve_names()
         +  3 0x809dff1 (from 0x809e804)     bacpy()
         +  3 0x80a46bb (from 0x809e81d)     adapter_search_found_devices()
         +  2 0x80a4642 (from 0x80892b0)    adapter_get_state()
         +  2 0x80a453a (from 0x80892fe)    adapter_set_state()
         +  3 0x80a4d46 (from 0x80a45e5)     adapter_update_oor_devices()
         +  3 0x80ac200 (from 0x80a4618)     emit_property_changed()
         +  4 0x80abf1d (from 0x80ac29c)      append_variant()
         +  4 0x804f543 (from 0x80ac2ae)      g_dbus_send_message()
         +  1 0x808812b (from 0x808a38a)   check_pending_hci_req()
         +  0 0x808a019 (from 0x17fdab)  io_security_event()
         +  1 0x8087c29 (from 0x808a121)   hci_test_bit()
         +  1 0x80893be (from 0x808a166)   cmd_status()
         +  1 0x808812b (from 0x808a38a)   check_pending_hci_req()
         +  0 0x804da4a (from 0x17fdab)  watch_func()
         +  1 0x804df9b (from 0x9cc0dd)   dispatch_status()
         +  2 0x804d9fb (from 0x804dfdd)    queue_dispatch()
         +  0 0x804d996 (from 0x14953c)  message_dispatch()
         +  1 0x8050409 (from 0x9cec8d)   message_filter()
         +  1 0x804ea38 (from 0x9dbf13)   generic_message()
         +  2 0x804e9b5 (from 0x804ea7b)    find_interface()
         +  2 0x80a0d23 (from 0x804eafd)    adapter_stop_discovery()
         +  3 0x809f488 (from 0x80a0d7f)     find_session()
         +  3 0x809f895 (from 0x80a0db2)     session_unref()
         +  4 0x8087840 (from 0x809f8f7)      btd_debug()
         +  4 0x809f7a8 (from 0x809f913)      session_free()
         +  5 0x8050a57 (from 0x809f7e3)       g_dbus_remove_watch()
         +  6 0x804fd59 (from 0x8050aa2)        filter_data_find_callback()
         +  6 0x804fd59 (from 0x8050aa2)        filter_data_find_callback()
         +  6 0x804fd59 (from 0x8050aa2)        filter_data_find_callback()
         +  6 0x804fd59 (from 0x8050aa2)        filter_data_find_callback()
         +  6 0x8050032 (from 0x8050abd) 
filter_data_remove_callback()
         +  7 0x804fb14 (from 0x80500db)         remove_match()
         +  8 0x804f8ea (from 0x804fb4e)          format_rule()
         +  8 0x804de1d (from 0x9e1783)          add_timeout()
         +  8 0x804df9b (from 0x9cc0dd)          dispatch_status()
         +  9 0x804d9fb (from 0x804dfdd)           queue_dispatch()
         +  8 0x804decc (from 0x9e16ff)          remove_timeout()
         +  8 0x804ddbf (from 0x9e1469)          timeout_handler_free()
         +  7 0x804fdf7 (from 0x805011d)         filter_data_free()
         +  7 0x804f790 (from 0x8050150)         filter_data_find()
         +  5 0x809f58c (from 0x809f7ee)       session_remove()
         +  6 0x8087840 (from 0x809f616)        btd_debug()
         +  6 0x8087840 (from 0x809f721)        btd_debug()
         +  6 0x809e6a8 (from 0x809f72c)        pending_remote_name_cancel()
         +  7 0x809dff1 (from 0x809e70e)         bacpy()
         +  7 0x80a46bb (from 0x809e727) 
adapter_search_found_devices()
         +  6 0x809e391 (from 0x809f737)        clear_found_devices_list()
         +  6 0x8085e04 (from 0x809f787)        hciops_stop_discovery()
         +  7 0x8084898 (from 0x8085e7b)         hci_test_bit()
         +  3 0x80877a4 (from 0x80a0dbe)     info()
         +  0 0x808a019 (from 0x17fdab)  io_security_event()
         +  1 0x8087c29 (from 0x808a121)   hci_test_bit()
         +  1 0x8089425 (from 0x808a187)   cmd_complete()
         +  2 0x80891f0 (from 0x808951e)    inquiry_complete()
         +  3 0x809d9c3 (from 0x808923f)     manager_find_adapter()
         +  4 0x809d8e3 (from 0x16847e)      adapter_cmp()
         +  5 0x80a44f7 (from 0x809d91b)       adapter_get_address()
         +  6 0x809dff1 (from 0x80a4525)        bacpy()
         +  5 0x809cf7c (from 0x809d92d)       bacmp()
         +  3 0x80a4642 (from 0x808926f)     adapter_get_state()
         +  3 0x80a453a (from 0x8089288)     adapter_set_state()
         +  1 0x808812b (from 0x808a38a)   check_pending_hci_req()
         +  0 0x804da4a (from 0x17fdab)  watch_func()
         +  1 0x804df9b (from 0x9cc0dd)   dispatch_status()
         +  2 0x804d9fb (from 0x804dfdd)    queue_dispatch()
         +  0 0x804d996 (from 0x14953c)  message_dispatch()
         +  1 0x8050409 (from 0x9cec8d)   message_filter()
         +  1 0x804ea38 (from 0x9dbf13)   generic_message()
         +  2 0x804e9b5 (from 0x804ea7b)    find_interface()
         +  2 0x80a0bde (from 0x804eafd)    adapter_start_discovery()
         +  3 0x809f488 (from 0x80a0c3d)     find_session()
         +  3 0x80a0b66 (from 0x80a0c92)     adapter_start_inquiry()
         +  4 0x809e6a8 (from 0x80a0ba4)      pending_remote_name_cancel()
         +  5 0x809dff1 (from 0x809e70e)       bacpy()
         +  5 0x80a46bb (from 0x809e727) 
adapter_search_found_devices()
         +  4 0x8085c9a (from 0x80a0bc1)      hciops_start_discovery()
         +  3 0x809ed21 (from 0x80a0cdd)     create_session()
         +  4 0x805092f (from 0x809ede5)      g_dbus_add_disconnect_watch()
         +  5 0x8050834 (from 0x8050978)       g_dbus_add_service_watch()
         +  6 0x804fbbb (from 0x8050898)        filter_data_get()
         +  7 0x804f790 (from 0x804fc08)         filter_data_find()
         +  7 0x804f790 (from 0x804fc6b)         filter_data_find()
         +  7 0x804fa5a (from 0x804fd0c)         add_match()
         +  8 0x804f8ea (from 0x804fa94)          format_rule()
         +  8 0x804de1d (from 0x9e1783)          add_timeout()
         +  8 0x804df9b (from 0x9cc0dd)          dispatch_status()
         +  9 0x804d9fb (from 0x804dfdd)           queue_dispatch()
         +  8 0x804decc (from 0x9e16ff)          remove_timeout()
         +  8 0x804ddbf (from 0x9e1469)          timeout_handler_free()
         +  6 0x804ff5d (from 0x80508d8)        filter_data_add_callback()
         +  4 0x80877a4 (from 0x809ee20)      info()
         +  4 0x809eca1 (from 0x809ee2b)      session_ref()
         +  5 0x8087840 (from 0x809ed03)       btd_debug()
         +  0 0x808a019 (from 0x17fdab)  io_security_event()
         +  1 0x8087c29 (from 0x808a121)   hci_test_bit()
         +  1 0x8089425 (from 0x808a187)   cmd_complete()
         +  2 0x80890df (from 0x80894fe)    start_inquiry()
         +  3 0x809d9c3 (from 0x808912e)     manager_find_adapter()
         +  4 0x809d8e3 (from 0x16847e)      adapter_cmp()
         +  5 0x80a44f7 (from 0x809d91b)       adapter_get_address()
         +  6 0x809dff1 (from 0x80a4525)        bacpy()
         +  5 0x809cf7c (from 0x809d92d)       bacmp()
         +  3 0x80a4642 (from 0x8089158)     adapter_get_state()
         +  3 0x80a543e (from 0x8089166)     adapter_has_discov_sessions()
         +  3 0x80a453a (from 0x808918a)     adapter_set_state()
         +  4 0x80ac200 (from 0x80a4618)      emit_property_changed()
         +  5 0x80abf1d (from 0x80ac29c)       append_variant()
         +  5 0x804f543 (from 0x80ac2ae)       g_dbus_send_message()
         +  1 0x808812b (from 0x808a38a)   check_pending_hci_req()
         +  0 0x80962cd (from 0x17fdab)  connect_watch()
         +  1 0x80a97cf (from 0x80964ae)   browse_cb()

Last call is search_cb I'm sure about it, thing is that the tracer only 
traces function when they exit, not when they get in.

I think the best way to solve this is that the device structure has a 
reference to the context so it can release it when it gets removed 
without any issue. We don't need the sdp callback if we no longer have a 
device anyway.

Manuel


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox