* MCAP patches @ 2010-07-28 8:00 Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 01/16] Initial support for MCAP Santiago Carot-Nemesio 2010-08-04 9:02 ` MCAP patches José Antonio Santos Cadenas 0 siblings, 2 replies; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:00 UTC (permalink / raw) To: linux-bluetooth Hello, Next are the patches that we have prepared for MCAP. Git can be cloned from git://gitorious.org/bluez-mcap-hdp/mcap-hdp.git Regards. ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 01/16] Initial support for MCAP 2010-07-28 8:00 MCAP patches Santiago Carot-Nemesio @ 2010-07-28 8:00 ` Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 02/16] Add MCAP instance management Santiago Carot-Nemesio 2010-08-04 9:02 ` MCAP patches José Antonio Santos Cadenas 1 sibling, 1 reply; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:00 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- Makefile.am | 12 +++++++++- acinclude.m4 | 6 +++++ health/mcap.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++ health/mcap.h | 38 +++++++++++++++++++++++++++++++++ health/mcap_lib.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+), 1 deletions(-) create mode 100644 health/mcap.c create mode 100644 health/mcap.h create mode 100644 health/mcap_lib.h diff --git a/Makefile.am b/Makefile.am index 65d4312..0781643 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,11 @@ builtin_modules += service builtin_sources += plugins/service.c endif +if MCAP +mcap_sources += health/mcap_lib.h \ + health/mcap.h health/mcap.c +endif + builtin_modules += hciops builtin_sources += plugins/hciops.c @@ -201,7 +207,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 +330,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)/health +endif pkgconfigdir = $(libdir)/pkgconfig diff --git a/acinclude.m4 b/acinclude.m4 index f5fdd66..239ccb1 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/health/mcap.c b/health/mcap.c new file mode 100644 index 0000000..c17546b --- /dev/null +++ b/health/mcap.c @@ -0,0 +1,55 @@ +/* + * + * 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 <stdlib.h> +#include <errno.h> + +#include "mcap.h" +#include "mcap_lib.h" + +struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter, + BtIOSecLevel sec, + uint16_t ccpsm, + uint16_t dcpsm, + 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, + GError **gerr) +{ + /* TODO: Create mcap_create_instance */ + return NULL; +} + +void mcap_release_instance(struct mcap_instance *mi) +{ + /* TODO: Create mcap_release_instance */ +} diff --git a/health/mcap.h b/health/mcap.h new file mode 100644 index 0000000..c1167fa --- /dev/null +++ b/health/mcap.h @@ -0,0 +1,38 @@ +/* + * + * 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 + +#ifdef __cplusplus +} +#endif + +#endif /* __MCAP_H */ diff --git a/health/mcap_lib.h b/health/mcap_lib.h new file mode 100644 index 0000000..714610e --- /dev/null +++ b/health/mcap_lib.h @@ -0,0 +1,61 @@ +/* + * + * 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> + +struct mcap_instance; +struct mcap_mcl; + +typedef void (* mcap_mcl_event_cb) (struct mcap_mcl *mcl, gpointer data); + +/* MCAP main operations */ + +struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter, + BtIOSecLevel sec, uint16_t ccpsm, + uint16_t dcpsm, + 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, + GError **gerr); + +void mcap_release_instance(struct mcap_instance *mi); + +#ifdef __cplusplus +} +#endif + +#endif /* __MCAP_LIB_H */ -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 02/16] Add MCAP instance management 2010-07-28 8:00 ` [PATCH 01/16] Initial support for MCAP Santiago Carot-Nemesio @ 2010-07-28 8:00 ` Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 03/16] Receive MCAP mcl connections from remote devices Santiago Carot-Nemesio 0 siblings, 1 reply; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:00 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- Makefile.am | 2 +- health/mcap.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++- health/mcap.h | 4 + health/mcap_internal.h | 52 ++++++++++++++++ health/mcap_lib.h | 30 +++++++++ 5 files changed, 237 insertions(+), 4 deletions(-) create mode 100644 health/mcap_internal.h diff --git a/Makefile.am b/Makefile.am index 0781643..c8bd62a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -170,7 +170,7 @@ builtin_sources += plugins/service.c endif if MCAP -mcap_sources += health/mcap_lib.h \ +mcap_sources += health/mcap_lib.h health/mcap_internal.h \ health/mcap.h health/mcap.c endif diff --git a/health/mcap.c b/health/mcap.c index c17546b..54e6355 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -33,6 +33,30 @@ #include "mcap.h" #include "mcap_lib.h" +#include "mcap_internal.h" + +#define MCAP_ERROR g_quark_from_static_string("mcap-error-quark") + + +static void mcap_mcl_shutdown(struct mcap_mcl *mcl) +{ + /* TODO: implement mcap_mcl_shutdown */ +} + +void mcap_mcl_unref(struct mcap_mcl *mcl) +{ + /* TODO: implement mcap_mcl_unref */ +} + +static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data) +{ + /* TODO: implement confirm_dc_event_cb */ +} + +static void confirm_mcl_event_cb(GIOChannel *chan, gpointer user_data) +{ + /* TODO: implement confirm_mcl_event_cb */ +} struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter, BtIOSecLevel sec, @@ -45,11 +69,134 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter, gpointer user_data, GError **gerr) { - /* TODO: Create mcap_create_instance */ - 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; + } + /* Initialize random seed to generate mdlids for this instance */ + srand(time(NULL)); + return ms; } void mcap_release_instance(struct mcap_instance *mi) { - /* TODO: Create mcap_release_instance */ + GSList *l; + + if (!mi) + return; + + if (mi->ccio) { + g_io_channel_shutdown(mi->ccio, TRUE, NULL); + g_io_channel_unref(mi->ccio); + mi->ccio = NULL; + } + + if (mi->dcio) { + g_io_channel_shutdown(mi->dcio, TRUE, NULL); + g_io_channel_unref(mi->dcio); + mi->dcio = NULL; + } + + for (l = mi->mcls; l; l = l->next) { + mcap_mcl_shutdown(l->data); + mcap_mcl_unref(l->data); + } + g_slist_free(mi->mcls); + mi->mcls = NULL; + + for (l = mi->cached; l; l = l->next) + mcap_mcl_unref(l->data); + g_slist_free(mi->cached); + mi->cached = NULL; + + g_free(mi); +} + +uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err) +{ + uint16_t lpsm; + + if (!(mi && mi->ccio)) { + g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, + "Invalid MCAP instance"); + return 0; + } + + bt_io_get(mi->ccio, BT_IO_L2CAP, err, + BT_IO_OPT_PSM, &lpsm, + BT_IO_OPT_INVALID); + if (*err) + return 0; + return lpsm; +} + +uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err) +{ + uint16_t lpsm; + + if (!(mi && mi->dcio)) { + g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, + "Invalid MCAP instance"); + return 0; + } + + bt_io_get(mi->dcio, BT_IO_L2CAP, err, + BT_IO_OPT_PSM, &lpsm, + BT_IO_OPT_INVALID); + if (*err) + return 0; + return lpsm; } diff --git a/health/mcap.h b/health/mcap.h index c1167fa..139b562 100644 --- a/health/mcap.h +++ b/health/mcap.h @@ -31,6 +31,10 @@ extern "C" { #endif +/* maximum transmission unit for channels */ +#define MCAP_CC_MTU 48 +#define MCAP_DC_MTU L2CAP_DEFAULT_MTU + #ifdef __cplusplus } #endif diff --git a/health/mcap_internal.h b/health/mcap_internal.h new file mode 100644 index 0000000..ed4ed58 --- /dev/null +++ b/health/mcap_internal.h @@ -0,0 +1,52 @@ +/* + * + * 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 + +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 */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __MCAP_INTERNAL_H */ diff --git a/health/mcap_lib.h b/health/mcap_lib.h index 714610e..81d8b14 100644 --- a/health/mcap_lib.h +++ b/health/mcap_lib.h @@ -35,11 +35,38 @@ extern "C" { #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_REQ_IGNORED, + MCAP_ERROR_MCL_CLOSED, + MCAP_ERROR_FAILED +} McapError; + struct mcap_instance; struct mcap_mcl; +/************ Callbacks ************/ + +/* mcl callbacks */ + typedef void (* mcap_mcl_event_cb) (struct mcap_mcl *mcl, gpointer data); +/************ Operations ************/ + /* MCAP main operations */ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter, @@ -54,6 +81,9 @@ struct mcap_instance *mcap_create_instance(struct btd_adapter *btd_adapter, void mcap_release_instance(struct mcap_instance *mi); +uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err); +uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err); + #ifdef __cplusplus } #endif -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 03/16] Receive MCAP mcl connections from remote devices 2010-07-28 8:00 ` [PATCH 02/16] Add MCAP instance management Santiago Carot-Nemesio @ 2010-07-28 8:00 ` Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 04/16] Added function for MCAP control channel (MCL) management Santiago Carot-Nemesio 0 siblings, 1 reply; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:00 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- health/mcap.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++- health/mcap.h | 21 +++++ health/mcap_internal.h | 52 ++++++++++++ health/mcap_lib.h | 15 ++++ 4 files changed, 295 insertions(+), 2 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index 54e6355..282580d 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -38,24 +38,229 @@ #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_shutdown(struct mcap_mcl *mcl) { /* TODO: implement mcap_mcl_shutdown */ } +static void mcap_mcl_release(struct mcap_mcl *mcl) +{ + /* TODO: implement mcap_mcl_release */ +} + +static void mcap_mcl_check_del(struct mcap_mcl *mcl) +{ + if (mcl->ctrl & MCAP_CTRL_CACHED) + mcap_mcl_shutdown(mcl); + else + mcap_mcl_unref(mcl); +} + +static void mcap_uncache_mcl(struct mcap_mcl *mcl) +{ + 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; +} + +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) { - /* TODO: implement mcap_mcl_unref */ + mcl->ref--; + + DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref); + + if ((mcl->ctrl & MCAP_CTRL_CACHED) && (mcl->ref < 2)) { + /* Free space in cache memory due any other profile has a local + * copy of current MCL stored in cache */ + DBG("Remove from cache (%p): ref=%d", mcl, mcl->ref); + mcl->ms->cached = g_slist_remove(mcl->ms->cached, mcl); + mcap_mcl_release(mcl); + return; + } + + if (mcl->ref > 0) + return; + + mcap_mcl_release(mcl); } +static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond, + gpointer data) +{ + /* TODO: Create mcl_control_cb */ + return FALSE; +} static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data) { /* TODO: implement confirm_dc_event_cb */ } +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: implement confirm_mcl_event_cb */ + 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->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1; + 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, diff --git a/health/mcap.h b/health/mcap.h index 139b562..a45cc8a 100644 --- a/health/mcap.h +++ b/health/mcap.h @@ -35,6 +35,27 @@ extern "C" { #define MCAP_CC_MTU 48 #define MCAP_DC_MTU L2CAP_DEFAULT_MTU +/* 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 + + #ifdef __cplusplus } #endif diff --git a/health/mcap_internal.h b/health/mcap_internal.h index ed4ed58..aab9e06 100644 --- a/health/mcap_internal.h +++ b/health/mcap_internal.h @@ -31,6 +31,33 @@ 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; + +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 */ @@ -45,6 +72,31 @@ struct mcap_instance { 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 */ + uint16_t next_mdl; /* id used to create next MDL */ +}; + +#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 */ + #ifdef __cplusplus } #endif diff --git a/health/mcap_lib.h b/health/mcap_lib.h index 81d8b14..fcf69ee 100644 --- a/health/mcap_lib.h +++ b/health/mcap_lib.h @@ -58,15 +58,30 @@ typedef enum { struct mcap_instance; struct mcap_mcl; +struct mcap_mdl; /************ Callbacks ************/ +/* mdl callbacks */ + +typedef void (* mcap_mdl_event_cb) (struct mcap_mdl *mdl, 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); /************ Operations ************/ +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, -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 04/16] Added function for MCAP control channel (MCL) management 2010-07-28 8:00 ` [PATCH 03/16] Receive MCAP mcl connections from remote devices Santiago Carot-Nemesio @ 2010-07-28 8:00 ` Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 05/16] Prepare FSM functions for processing comands Santiago Carot-Nemesio 0 siblings, 1 reply; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:00 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- health/mcap.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap_lib.h | 30 ++++++ 2 files changed, 298 insertions(+), 2 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index 282580d..ba2b2ad 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -37,6 +37,16 @@ #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) + +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 */ +}; static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data) { @@ -103,14 +113,59 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr) return NULL; } +static void mcap_free_mdls(struct mcap_mcl *mcl, gboolean save) +{ + /* TODO: implement mcap_free_mdls */ +} + +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) { - /* TODO: implement mcap_mcl_shutdown */ + close_mcl(mcl, TRUE); } static void mcap_mcl_release(struct mcap_mcl *mcl) { - /* TODO: implement mcap_mcl_release */ + close_mcl(mcl, FALSE); } static void mcap_mcl_check_del(struct mcap_mcl *mcl) @@ -134,6 +189,23 @@ static void mcap_uncache_mcl(struct mcap_mcl *mcl) 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) { mcl->ref++; @@ -164,12 +236,206 @@ 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, gpointer user_data, GError **gerr, + 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; +} + +void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr) +{ + bacpy(addr, &mcl->addr); +} + static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { /* TODO: Create mcl_control_cb */ 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); + } +} + +void mcap_create_mcl(struct mcap_instance *ms, + const bdaddr_t *addr, + uint16_t ccpsm, + mcap_mcl_connect_cb connect_cb, + gpointer user_data, + GError **err) +{ + 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->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1; + 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) { /* TODO: implement confirm_dc_event_cb */ diff --git a/health/mcap_lib.h b/health/mcap_lib.h index fcf69ee..b4e9c16 100644 --- a/health/mcap_lib.h +++ b/health/mcap_lib.h @@ -56,6 +56,16 @@ typedef enum { 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; @@ -65,6 +75,11 @@ struct mcap_mdl; /* 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_notify_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, @@ -76,9 +91,24 @@ typedef uint8_t (* mcap_remote_mdl_reconn_req_cb) (struct mcap_mdl *mdl, /* 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 ************/ +/* Mcl operations*/ + +void mcap_create_mcl(struct mcap_instance *ms, + const bdaddr_t *addr, + uint16_t ccpsm, + mcap_mcl_connect_cb connect_cb, + gpointer user_data, + GError **err); +void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache); +void mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data, GError **gerr, + McapMclCb cb1, ...); +void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr); + struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl); void mcap_mcl_unref(struct mcap_mcl *mcl); -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 05/16] Prepare FSM functions for processing comands 2010-07-28 8:00 ` [PATCH 04/16] Added function for MCAP control channel (MCL) management Santiago Carot-Nemesio @ 2010-07-28 8:00 ` Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 06/16] Send MCAP request mcap_md_create_mdl_req Santiago Carot-Nemesio 0 siblings, 1 reply; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:00 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- health/mcap.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++- health/mcap.h | 29 +++++++ health/mcap_internal.h | 4 + 3 files changed, 224 insertions(+), 1 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index ba2b2ad..73562c3 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -35,6 +35,8 @@ #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 { \ @@ -48,6 +50,17 @@ struct connect_mcl { 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); +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"); @@ -98,6 +111,50 @@ static void set_default_cb(struct mcap_mcl *mcl) mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb; } +static void mcap_notify_error(struct mcap_mcl *mcl, GError *err) +{ + /* TODO: implement mcap_notify_error */ +} + +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 mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc, + uint16_t mdl, uint8_t *data, size_t len) +{ + mcap_rsp *cmd; + uint8_t *rsp; + int sock, sent; + + if (mcl->cc == NULL) + return -1; + + sock = g_io_channel_unix_get_fd(mcl->cc); + + rsp = g_malloc(sizeof(mcap_rsp) + len); + cmd = (mcap_rsp *)rsp; + cmd->op = oc; + cmd->rc = rc; + cmd->mdl = htons(mdl); + + if (data && len > 0) + memcpy(rsp + sizeof(mcap_rsp), data, len); + + sent = mcap_send_data(sock, rsp, sizeof(mcap_rsp) + len); + g_free(rsp); + return sent; +} + static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr) { GSList *l; @@ -176,6 +233,46 @@ static void mcap_mcl_check_del(struct mcap_mcl *mcl) mcap_mcl_unref(mcl); } +static void mcap_cache_mcl(struct mcap_mcl *mcl) +{ + 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) { if (!(mcl->ctrl & MCAP_CTRL_CACHED)) @@ -318,10 +415,103 @@ void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr) bacpy(addr, &mcl->addr); } +/* 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: Implement proc_req_connected */ +} + +static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + /* TODO: Implement proc_req_pending */ +} + +static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + /* TODO: Implement proc_req_active */ +} + +static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + /* TODO: Implement proc_response */ +} + +static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + GError *gerr = NULL; + + if (cmd[0] > MCAP_MD_SYNC_INFO_IND || + (cmd[0] > MCAP_MD_DELETE_MDL_RSP && + cmd[0] < MCAP_MD_SYNC_CAP_REQ)) { + error("Unknown cmd received (op code = %d)", cmd[0]); + mcap_send_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE, + MCAP_MDLID_RESERVED, NULL, 0); + return; + } + + if (cmd[0] >= MCAP_MD_SYNC_CAP_REQ && + cmd[0] <= MCAP_MD_SYNC_INFO_IND) { + /* TODO: proc_sync_cmd(mcl, cmd, len);*/ + 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; + /* Initiator will ignore our last request */ + proc_req[mcl->state](mcl, cmd, len); + RELEASE_TIMER(mcl); + mcl->req = MCL_AVAILABLE; + g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQ_IGNORED, + "Initiator sent a request with more priority"); + mcap_notify_error(mcl, gerr); + 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: Create mcl_control_cb */ + GError *gerr = NULL; + + 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) { + if (mcl->req == MCL_WAITING_RSP) { + /* notify error in pending callback */ + g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_MCL_CLOSED, + "MCL closed"); + 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; } diff --git a/health/mcap.h b/health/mcap.h index a45cc8a..523be90 100644 --- a/health/mcap.h +++ b/health/mcap.h @@ -35,6 +35,25 @@ extern "C" { #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 @@ -55,6 +74,16 @@ extern "C" { #define MCAP_MDLID_FINAL 0xFEFF #define MCAP_ALL_MDLIDS 0xFFFF +/* + * MCAP Response Packet Format + */ + +typedef struct { + uint8_t op; + uint8_t rc; + uint16_t mdl; +} __attribute__ ((packed)) mcap_rsp; + #ifdef __cplusplus } diff --git a/health/mcap_internal.h b/health/mcap_internal.h index aab9e06..cc81692 100644 --- a/health/mcap_internal.h +++ b/health/mcap_internal.h @@ -97,6 +97,10 @@ struct mcap_mcl { #define MCAP_CTRL_FREE 0x10 /* MCL is marked as releasable */ #define MCAP_CTRL_NOCACHE 0x20 /* MCL is marked as not cacheable */ +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); + #ifdef __cplusplus } #endif -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 06/16] Send MCAP request mcap_md_create_mdl_req 2010-07-28 8:00 ` [PATCH 05/16] Prepare FSM functions for processing comands Santiago Carot-Nemesio @ 2010-07-28 8:00 ` Santiago Carot-Nemesio 2010-07-28 8:03 ` [PATCH 07/16] Process " Jose Antonio Santos Cadenas 0 siblings, 1 reply; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:00 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- health/mcap.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++ health/mcap.h | 11 +++ health/mcap_internal.h | 16 ++++ health/mcap_lib.h | 9 +++ 4 files changed, 214 insertions(+), 0 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index 73562c3..7366c66 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -35,6 +35,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") @@ -50,6 +51,18 @@ 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_notify_cb notify; +} 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); static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l); @@ -61,6 +74,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"); @@ -111,6 +126,43 @@ 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, void *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) { /* TODO: implement mcap_notify_error */ @@ -155,6 +207,132 @@ static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc, return sent; } +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 uint16_t generate_mdlid(struct mcap_mcl *mcl) +{ + uint16_t mdlid = mcl->next_mdl; + struct mcap_mdl *mdl; + + do { + mdl = get_mdl(mcl, mdlid); + if (!mdl) { + mcl->next_mdl = (mdlid % MCAP_MDLID_FINAL) + 1; + return mdlid; + } else + mdlid = (mdlid % MCAP_MDLID_FINAL) + 1; + } while (mdlid != mcl->next_mdl); + + /* No more mdlids availables */ + return 0; +} + +static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep, + uint8_t conf) +{ + mcap_md_create_mdl_req *req_mdl; + + req_mdl = g_malloc0(sizeof(mcap_md_create_mdl_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_mdl; +} + +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 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_create_mdl(struct mcap_mcl *mcl, + uint8_t mdepid, + uint8_t conf, + mcap_mdl_operation_conf_cb connect_cb, + gpointer user_data, + GError **err) +{ + struct mcap_mdl *mdl; + struct mcap_mdl_op_cb *con; + mcap_md_create_mdl_req *cmd; + 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 struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr) { GSList *l; diff --git a/health/mcap.h b/health/mcap.h index 523be90..8c3679f 100644 --- a/health/mcap.h +++ b/health/mcap.h @@ -75,6 +75,17 @@ extern "C" { #define MCAP_ALL_MDLIDS 0xFFFF /* + * 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; + +/* * MCAP Response Packet Format */ diff --git a/health/mcap_internal.h b/health/mcap_internal.h index cc81692..d639cdb 100644 --- a/health/mcap_internal.h +++ b/health/mcap_internal.h @@ -48,6 +48,13 @@ typedef enum { 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 */ @@ -97,6 +104,15 @@ struct mcap_mcl { #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); diff --git a/health/mcap_lib.h b/health/mcap_lib.h index b4e9c16..d8fb863 100644 --- a/health/mcap_lib.h +++ b/health/mcap_lib.h @@ -96,6 +96,15 @@ typedef void (* mcap_mcl_connect_cb) (struct mcap_mcl *mcl, GError *err, /************ Operations ************/ +/* Mdl operations*/ + +void mcap_create_mdl(struct mcap_mcl *mcl, + uint8_t mdepid, + uint8_t conf, + mcap_mdl_operation_conf_cb connect_cb, + gpointer user_data, + GError **err); + /* Mcl operations*/ void mcap_create_mcl(struct mcap_instance *ms, -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 07/16] Process MCAP request mcap_md_create_mdl_req 2010-07-28 8:00 ` [PATCH 06/16] Send MCAP request mcap_md_create_mdl_req Santiago Carot-Nemesio @ 2010-07-28 8:03 ` Jose Antonio Santos Cadenas 2010-07-28 8:03 ` [PATCH 08/16] Process MCAP response mcap_md_create_mdl_rsp Jose Antonio Santos Cadenas 0 siblings, 1 reply; 18+ messages in thread From: Jose Antonio Santos Cadenas @ 2010-07-28 8:03 UTC (permalink / raw) To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas --- health/mcap.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap.h | 5 + 2 files changed, 255 insertions(+), 5 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index 7366c66..9bb81cf 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -163,9 +163,103 @@ static void mcap_send_std_opcode(struct mcap_mcl *mcl, void *cmd, mcl->req = MCL_WAITING_RSP; } +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 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 gint cmp_mdl_state(gconstpointer a, gconstpointer b) +{ + const struct mcap_mdl *mdl = a; + const MDLState *st = b; + + if (mdl->state == *st) + return 0; + else if (mdl->state < *st) + return -1; + else + return 1; +} + static void mcap_notify_error(struct mcap_mcl *mcl, GError *err) { - /* TODO: implement mcap_notify_error */ + struct mcap_mdl_op_cb *con = mcl->priv_data; + struct mcap_mdl *mdl; + MDLState st; + GSList *l; + + if (!con || !mcl->lcmd) + return; + + switch (mcl->lcmd[0]){ + case MCAP_MD_CREATE_MDL_REQ: + st = MDL_WAITING; + l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); + mdl = l->data; + mcl->mdls = g_slist_remove(mcl->mdls, mdl); + g_free(mdl); + update_mcl_state(mcl); + con->cb.op_conf(NULL, 0, err, con->user_data); + break; + case MCAP_MD_ABORT_MDL_REQ: + st = MDL_WAITING; + l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); + shutdown_mdl(l->data); + update_mcl_state(mcl); + con->cb.notify(err, con->user_data); + break; + case MCAP_MD_DELETE_MDL_REQ: + for (l = mcl->mdls; l; l = l->next) { + mdl = l->data; + if (mdl->state == MDL_DELETING) + mdl->state = (mdl->dc) ? MDL_CONNECTED : + MDL_CLOSED; + } + update_mcl_state(mcl); + con->cb.notify(err, con->user_data); + break; + case MCAP_MD_RECONNECT_MDL_REQ: + st = MDL_WAITING; + l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); + shutdown_mdl(l->data); + update_mcl_state(mcl); + con->cb.op(NULL, err, con->user_data); + break; + } + + g_free(mcl->priv_data); + mcl->priv_data = NULL; + + g_free(mcl->lcmd); + mcl->lcmd = NULL; } int mcap_send_data(int sock, const uint8_t *buf, uint32_t size) @@ -350,7 +444,23 @@ static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr) static void mcap_free_mdls(struct mcap_mcl *mcl, gboolean save) { - /* TODO: implement mcap_free_mdls */ + 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) @@ -593,20 +703,155 @@ void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr) bacpy(addr, &mcl->addr); } +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)) { + mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, + MCAP_INVALID_PARAM_VALUE, + MCAP_MDLID_RESERVED, + NULL, 0); + return; + } + + req = (mcap_md_create_mdl_req *)cmd; + + mdl_id = ntohs(req->mdl); + if (mdl_id < MCAP_MDLID_INITIAL || mdl_id > MCAP_MDLID_FINAL) { + mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL, + mdl_id, NULL, 0); + return; + } + + mdep_id = req->mdep; + if (mdep_id > MCAP_MDEPID_FINAL) { + mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP, + mdl_id, NULL, 0); + return; + } + + mdl = get_mdl(mcl, mdl_id); + if (mdl && (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING )) { + /* Creation request arrives for a MDL that is being managed + * at current moment */ + mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY, + mdl_id, NULL, 0); + 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 */ + mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, + MCAP_UNSPECIFIED_ERROR, mdl_id, NULL, 0); + return; + } + if (rsp != MCAP_SUCCESS) { + mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id, + NULL, 0); + return; + } + + if (!mdl) { + mdl = g_malloc0(sizeof(struct mcap_mdl)); + mdl->mcl = mcl; + mdl->mdlid = mdl_id; + mcl->mdls = g_slist_insert_sorted(mcl->mdls, mdl, compare_mdl); + } 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->state = MCL_PENDING; + mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id, + &conf, 1); +} + +static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, + uint32_t len) +{ + /* TODO: Implement process_md_reconnect_mdl_req */ +} + +static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, + uint32_t len) +{ + /* TODO: Implement process_md_abort_mdl_req */ +} + +static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, + uint32_t len) +{ + /* TODO: Implement process_md_delete_mdl_req */ +} + +static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + /* TODO: Implements invalid_req_state */ +} + /* 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: Implement proc_req_connected */ + 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: + invalid_req_state(mcl, cmd, len); + } } static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { - /* TODO: Implement proc_req_pending */ + if (cmd[0] == MCAP_MD_ABORT_MDL_REQ) + process_md_abort_mdl_req(mcl, cmd, len); + else + invalid_req_state(mcl, cmd, len); } static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { - /* TODO: Implement proc_req_active */ + 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: + invalid_req_state(mcl, cmd, len); + } } static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) diff --git a/health/mcap.h b/health/mcap.h index 8c3679f..d0d552a 100644 --- a/health/mcap.h +++ b/health/mcap.h @@ -74,6 +74,11 @@ extern "C" { #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 */ -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 08/16] Process MCAP response mcap_md_create_mdl_rsp 2010-07-28 8:03 ` [PATCH 07/16] Process " Jose Antonio Santos Cadenas @ 2010-07-28 8:03 ` Jose Antonio Santos Cadenas 2010-07-28 8:03 ` [PATCH 09/16] Implement connection of MCAP data links (MDL's) Jose Antonio Santos Cadenas 0 siblings, 1 reply; 18+ messages in thread From: Jose Antonio Santos Cadenas @ 2010-07-28 8:03 UTC (permalink / raw) To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas --- health/mcap.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap.h | 6 ++ 2 files changed, 200 insertions(+), 1 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index 9bb81cf..734c6be 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -126,6 +126,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, void *cmd, uint32_t size, GError **err) { @@ -854,9 +886,170 @@ static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) } } +/* Function used to process replies */ +static gboolean check_err_rsp(struct mcap_mcl *mcl, uint8_t *cmd, + uint32_t rlen, uint32_t len, GError **gerr) +{ + mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd; + gint err = MCAP_ERROR_FAILED; + gboolean close = FALSE; + uint16_t rmdl, smdl; + mcap_rsp *rsp; + char *msg; + + if (cmd[0] == MCAP_ERROR_RSP) { + msg = "MCAP_ERROR_RSP received"; + close = TRUE; + goto fail; + } + + /* Check if the response matches with the last request */ + if (rlen < sizeof(mcap_rsp) || (mcl->lcmd[0] + 1) != cmd[0]) { + msg = "Protocol error"; + close = TRUE; + goto fail; + } + + if (rlen < len) { + msg = "Protocol error"; + close = TRUE; + goto fail; + } + + rsp = (mcap_rsp *)cmd; + smdl = ntohs(cmdlast->mdl); + rmdl = ntohs(rsp->mdl); + if (rmdl != smdl) { + msg = "MDLID received doesn't match with MDLID sent"; + close = TRUE; + goto fail; + } + + if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) { + msg = "Remote does not support opcodes"; + mcl->ctrl &= ~MCAP_CTRL_STD_OP; + goto fail; + } + + if (rsp->rc == MCAP_UNSPECIFIED_ERROR) { + msg = "Unspecified error"; + close = TRUE; + goto fail; + } + + if (rsp->rc != MCAP_SUCCESS) { + msg = error2str(rsp->rc); + err = rsp->rc; + goto fail; + } + + return FALSE; + +fail: + g_set_error(gerr, MCAP_ERROR, err, "%s", msg); + return close; +} + +static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl, + uint8_t *cmd, uint32_t len) +{ + mcap_md_create_mdl_req *cmdlast = (mcap_md_create_mdl_req *)mcl->lcmd; + struct mcap_mdl_op_cb *conn = mcl->priv_data; + mcap_mdl_operation_conf_cb connect_cb = conn->cb.op_conf; + gpointer user_data = conn->user_data; + struct mcap_mdl *mdl = conn->mdl; + uint8_t conf = cmdlast->conf; + gboolean close = FALSE; + GError *gerr = NULL; + uint8_t *param; + + g_free(mcl->priv_data); + mcl->priv_data = NULL; + + close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp) + 1, &gerr); + g_free(mcl->lcmd); + mcl->lcmd = NULL; + mcl->req = MCL_AVAILABLE; + + if (gerr) + goto fail; + + if (len < sizeof(mcap_rsp)) { + g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED, + "Protocol error"); + close = TRUE; + goto fail; + } + + param = cmd + sizeof(mcap_rsp); + /* Check if preferences changed */ + if (conf != 0x00 && *param != conf) { + g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED, + "Configuration changed"); + close = TRUE; + goto fail; + } + + connect_cb(mdl, *param, gerr, user_data); + return close; +fail: + connect_cb(NULL, 0, gerr, user_data); + mcl->mdls = g_slist_remove(mcl->mdls, mdl); + g_free(mdl); + g_error_free(gerr); + update_mcl_state(mcl); + return close; +} + +static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl, + uint8_t *cmd, uint32_t len) +{ + /* TODO: Implement process_md_reconnect_mdl_rsp */ + return TRUE; +} + +static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl, + uint8_t *cmd, uint32_t len) +{ + /* TODO: Implement process_md_abort_mdl_rsp */ + return TRUE; +} + +static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd, + uint32_t len) +{ + /* TODO: Implement process_md_delete_mdl_rsp */ + return TRUE; +} + static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { - /* TODO: Implement proc_response */ + gboolean close; + RELEASE_TIMER(mcl); + + switch (mcl->lcmd[0] + 1) { + case MCAP_MD_CREATE_MDL_RSP: + close = process_md_create_mdl_rsp(mcl, cmd, len); + break; + case MCAP_MD_RECONNECT_MDL_RSP: + close = process_md_reconnect_mdl_rsp(mcl, cmd, len); + break; + case MCAP_MD_ABORT_MDL_RSP: + close = process_md_abort_mdl_rsp(mcl, cmd, len); + break; + case MCAP_MD_DELETE_MDL_RSP: + close = process_md_delete_mdl_rsp(mcl, cmd, len); + break; + default: + DBG("Unknown cmd response received (op code = %d)",cmd[0]); + close = TRUE; + break; + } + + if (close) { + mcl->ms->mcl_disconnected_cb(mcl, mcl->ms->user_data); + mcap_cache_mcl(mcl); + } } static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) diff --git a/health/mcap.h b/health/mcap.h index d0d552a..1c72080 100644 --- a/health/mcap.h +++ b/health/mcap.h @@ -90,6 +90,12 @@ typedef struct { 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 */ -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 09/16] Implement connection of MCAP data links (MDL's) 2010-07-28 8:03 ` [PATCH 08/16] Process MCAP response mcap_md_create_mdl_rsp Jose Antonio Santos Cadenas @ 2010-07-28 8:03 ` Jose Antonio Santos Cadenas 2010-07-28 8:03 ` [PATCH 10/16] Process MCAP process_md_abort_mdl request and response commands Jose Antonio Santos Cadenas 0 siblings, 1 reply; 18+ messages in thread From: Jose Antonio Santos Cadenas @ 2010-07-28 8:03 UTC (permalink / raw) To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas --- health/mcap.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap_lib.h | 6 ++ 2 files changed, 137 insertions(+), 1 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index 734c6be..ecaa43f 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -1097,6 +1097,87 @@ 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 void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err, + gpointer data) +{ + struct mcap_mdl_op_cb *con = data; + struct mcap_mdl *mdl = con->mdl; + mcap_mdl_operation_cb cb = con->cb.op; + gpointer user_data = con->user_data; + + g_free(con); + DBG("mdl connect callback"); + + if (conn_err) { + DBG("ERROR: mdl connect callback"); + mdl->state = MDL_CLOSED; + g_io_channel_unref(mdl->dc); + mdl->dc = NULL; + cb(mdl, conn_err, user_data); + return; + } + + mdl->state = MDL_CONNECTED; + mdl->wid = g_io_add_watch(mdl->dc, G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) mdl_event_cb, mdl); + + cb(mdl, conn_err, user_data); +} + +void mcap_connect_mdl(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm, + mcap_mdl_operation_cb connect_cb, gpointer user_data, GError **err) +{ + struct mcap_mdl_op_cb *con; + + if (mdl->state != MDL_WAITING) { + g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL, + "%s", error2str(MCAP_INVALID_MDL)); + return; + } + + con = g_new0(struct mcap_mdl_op_cb, 1); + con->mdl = mdl; + con->cb.op = connect_cb; + con->user_data = user_data; + + /* TODO: Check if BtIOType is ERTM or Streaming before continue */ + + mdl->dc = bt_io_connect(BtType, mcap_connect_mdl_cb, con, + NULL, err, + BT_IO_OPT_SOURCE_BDADDR, &mdl->mcl->ms->src, + BT_IO_OPT_DEST_BDADDR, &mdl->mcl->addr, + BT_IO_OPT_PSM, dcpsm, + BT_IO_OPT_MTU, MCAP_DC_MTU, + BT_IO_OPT_SEC_LEVEL, mdl->mcl->ms->sec, + BT_IO_OPT_INVALID); + if (*err) { + DBG("MDL Connection error"); + mdl->state = MDL_CLOSED; + g_free(con); + } +} + static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { @@ -1191,6 +1272,21 @@ static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err, } } +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); +} + void mcap_create_mcl(struct mcap_instance *ms, const bdaddr_t *addr, uint16_t ccpsm, @@ -1244,7 +1340,41 @@ void mcap_create_mcl(struct mcap_instance *ms, static void confirm_dc_event_cb(GIOChannel *chan, gpointer user_data) { - /* TODO: implement confirm_dc_event_cb */ + 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); + mdl->state = MDL_CLOSED; + 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, diff --git a/health/mcap_lib.h b/health/mcap_lib.h index d8fb863..7bdcbc5 100644 --- a/health/mcap_lib.h +++ b/health/mcap_lib.h @@ -104,6 +104,12 @@ void mcap_create_mdl(struct mcap_mcl *mcl, mcap_mdl_operation_conf_cb connect_cb, gpointer user_data, GError **err); +void mcap_connect_mdl(struct mcap_mdl *mdl, + BtIOType BtType, + uint16_t dcpsm, + mcap_mdl_operation_cb connect_cb, + gpointer user_data, + GError **err); /* Mcl operations*/ -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 10/16] Process MCAP process_md_abort_mdl request and response commands 2010-07-28 8:03 ` [PATCH 09/16] Implement connection of MCAP data links (MDL's) Jose Antonio Santos Cadenas @ 2010-07-28 8:03 ` Jose Antonio Santos Cadenas 2010-07-28 8:03 ` [PATCH 11/16] Process MCAP process_md_reconnect_mdl " Jose Antonio Santos Cadenas 0 siblings, 1 reply; 18+ messages in thread From: Jose Antonio Santos Cadenas @ 2010-07-28 8:03 UTC (permalink / raw) To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas --- health/mcap.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap_lib.h | 4 ++ 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index ecaa43f..6006c2a 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -365,6 +365,18 @@ static uint16_t generate_mdlid(struct mcap_mcl *mcl) return 0; } +static mcap_md_req *create_req(uint8_t op, uint16_t mdl_id) +{ + mcap_md_req *req_cmd; + + req_cmd = g_malloc0(sizeof(mcap_md_req)); + + req_cmd->op = op; + req_cmd->mdl = htons(mdl_id); + + return req_cmd; +} + static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep, uint8_t conf) { @@ -459,6 +471,38 @@ void mcap_create_mdl(struct mcap_mcl *mcl, mcl); } +void mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb, + gpointer user_data, GError **err) +{ + struct mcap_mdl_op_cb *con; + struct mcap_mcl *mcl = mdl->mcl; + mcap_md_req *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.notify = abort_cb; + con->user_data = user_data; + + mcl->priv_data = con; + + mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer, + mcl); +} + static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr) { GSList *l; @@ -829,7 +873,45 @@ static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { - /* TODO: Implement process_md_abort_mdl_req */ + mcap_md_req *req; + GSList *l; + struct mcap_mdl *mdl, *abrt; + uint16_t mdl_id; + + if (len != sizeof(mcap_md_req)) { + mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, + MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED, NULL, 0); + 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) { + abrt = mdl; + if (mcl->state != MCL_CONNECTED) + break; + continue; + } + if (mdl->state == MDL_CONNECTED && mcl->state != MCL_ACTIVE) + mcl->state = MCL_ACTIVE; + + if (abrt && mcl->state == MCL_ACTIVE) + break; + } + + if (!abrt) { + mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL, + mdl_id, NULL, 0); + return; + } + + mcl->cb->mdl_aborted(abrt, mcl->cb->user_data); + abrt->state = MDL_CLOSED; + mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id, + NULL, 0); } static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, @@ -1011,8 +1093,36 @@ static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl, static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { - /* TODO: Implement process_md_abort_mdl_rsp */ - return TRUE; + struct mcap_mdl_op_cb *abrt = mcl->priv_data; + mcap_mdl_notify_cb abrt_cb = abrt->cb.notify; + gpointer user_data = abrt->user_data; + struct mcap_mdl *mdl = abrt->mdl; + mcap_rsp *rsp = (mcap_rsp *)cmd; + GError *gerr = NULL; + gboolean close = FALSE; + + g_free(mcl->priv_data); + mcl->priv_data = NULL; + + close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr); + + g_free(mcl->lcmd); + mcl->lcmd = NULL; + mcl->req = MCL_AVAILABLE; + + abrt_cb(gerr, user_data); + shutdown_mdl(mdl); + + if (len >= sizeof(mcap_rsp) && rsp->rc == MCAP_INVALID_MDL) { + mcl->mdls = g_slist_remove(mcl->mdls, mdl); + g_free(mdl); + } + + if (!gerr) + g_error_free(gerr); + + update_mcl_state(mcl); + return close; } static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd, diff --git a/health/mcap_lib.h b/health/mcap_lib.h index 7bdcbc5..106c1c7 100644 --- a/health/mcap_lib.h +++ b/health/mcap_lib.h @@ -110,6 +110,10 @@ void mcap_connect_mdl(struct mcap_mdl *mdl, mcap_mdl_operation_cb connect_cb, gpointer user_data, GError **err); +void mcap_mdl_abort(struct mcap_mdl *mdl, + mcap_mdl_notify_cb abort_cb, + gpointer user_data, + GError **err); /* Mcl operations*/ -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 11/16] Process MCAP process_md_reconnect_mdl request and response commands 2010-07-28 8:03 ` [PATCH 10/16] Process MCAP process_md_abort_mdl request and response commands Jose Antonio Santos Cadenas @ 2010-07-28 8:03 ` Jose Antonio Santos Cadenas 2010-07-28 8:03 ` [PATCH 12/16] Process MCAP process_md_delete_mdl " Jose Antonio Santos Cadenas 0 siblings, 1 reply; 18+ messages in thread From: Jose Antonio Santos Cadenas @ 2010-07-28 8:03 UTC (permalink / raw) To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas --- health/mcap.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap_lib.h | 4 ++ 2 files changed, 122 insertions(+), 3 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index 6006c2a..18749e3 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -471,6 +471,43 @@ void mcap_create_mdl(struct mcap_mcl *mcl, mcl); } +void mcap_reconnect_mdl(struct mcap_mdl *mdl, + mcap_mdl_operation_cb reconnect_cb, + gpointer user_data, + GError **err) +{ + struct mcap_mdl_op_cb *con; + struct mcap_mcl *mcl = mdl->mcl; + mcap_md_req *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); +} + void mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb, gpointer user_data, GError **err) { @@ -867,7 +904,53 @@ static void process_md_create_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { - /* TODO: Implement process_md_reconnect_mdl_req */ + mcap_md_req *req; + struct mcap_mdl *mdl; + uint16_t mdl_id; + uint8_t rsp; + + if (len != sizeof(mcap_md_req)) { + mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, + MCAP_INVALID_PARAM_VALUE, + MCAP_MDLID_RESERVED, + NULL, 0); + return; + } + + req = (mcap_md_req *)cmd; + mdl_id = ntohs(req->mdl); + + mdl = get_mdl(mcl, mdl_id); + if (!mdl) { + mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_INVALID_MDL, + mdl_id, NULL, 0); + return; + } else if (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING ) { + /* Creation request arrives for a MDL that is being managed + * at current moment */ + mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY, + mdl_id, NULL, 0); + 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) { + mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id, + NULL, 0); + return; + } + + if (mdl->state == MDL_CONNECTED) + shutdown_mdl(mdl); + + mdl->state = MDL_WAITING; + mcl->state = MCL_PENDING; + mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id, + NULL, 0); } static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, @@ -1086,8 +1169,40 @@ fail: static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { - /* TODO: Implement process_md_reconnect_mdl_rsp */ - return TRUE; + struct mcap_mdl_op_cb *reconn = mcl->priv_data; + mcap_mdl_operation_cb reconn_cb = reconn->cb.op; + gpointer user_data = reconn->user_data; + struct mcap_mdl *mdl = reconn->mdl; + mcap_rsp *rsp = (mcap_rsp *)cmd; + GError *gerr = NULL; + gboolean close = FALSE; + + g_free(mcl->priv_data); + mcl->priv_data = NULL; + + close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr); + + g_free(mcl->lcmd); + mcl->lcmd = NULL; + mcl->req = MCL_AVAILABLE; + + reconn_cb(mdl, gerr, user_data); + if (!gerr) + return close; + + g_error_free(gerr); + shutdown_mdl(mdl); + update_mcl_state(mcl); + + if (rsp->rc != MCAP_INVALID_MDL) + return close; + + /* Remove cached mdlid */ + mcl->mdls = g_slist_remove(mcl->mdls, mdl); + mcl->cb->mdl_deleted(mdl, mcl->cb->user_data); + g_free(mdl); + + return close; } static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl, diff --git a/health/mcap_lib.h b/health/mcap_lib.h index 106c1c7..fbf97df 100644 --- a/health/mcap_lib.h +++ b/health/mcap_lib.h @@ -104,6 +104,10 @@ void mcap_create_mdl(struct mcap_mcl *mcl, mcap_mdl_operation_conf_cb connect_cb, gpointer user_data, GError **err); +void mcap_reconnect_mdl(struct mcap_mdl *mdl, + mcap_mdl_operation_cb reconnect_cb, + gpointer user_data, + GError **err); void mcap_connect_mdl(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm, -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 12/16] Process MCAP process_md_delete_mdl request and response commands 2010-07-28 8:03 ` [PATCH 11/16] Process MCAP process_md_reconnect_mdl " Jose Antonio Santos Cadenas @ 2010-07-28 8:03 ` Jose Antonio Santos Cadenas 2010-07-28 8:07 ` [PATCH 13/16] Add functions for getting mdl properties Santiago Carot-Nemesio 0 siblings, 1 reply; 18+ messages in thread From: Jose Antonio Santos Cadenas @ 2010-07-28 8:03 UTC (permalink / raw) To: linux-bluetooth; +Cc: Jose Antonio Santos Cadenas --- health/mcap.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++- health/mcap_lib.h | 8 ++ 2 files changed, 208 insertions(+), 3 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index 18749e3..050a896 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -508,6 +508,86 @@ void mcap_reconnect_mdl(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) +{ + mcap_md_req *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_delete_all_mdls(struct mcap_mcl *mcl, mcap_mdl_notify_cb delete_cb, + gpointer user_data, GError **err) +{ + 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.notify = delete_cb; + con->user_data = user_data; + + send_delete_req(err, mcl, con, MCAP_ALL_MDLIDS); + if (*err) + g_free(con); +} + +void mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb, + gpointer user_data, GError **err) +{ + 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.notify = delete_cb; + con->user_data = user_data; + + send_delete_req(err, mcl, con, mdl->mdlid); + if (*err) + g_free(con); +} + void mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb, gpointer user_data, GError **err) { @@ -816,6 +896,18 @@ void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr) bacpy(addr, &mcl->addr); } +static void mcap_del_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) { @@ -1000,7 +1092,58 @@ static void process_md_abort_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, static void process_md_delete_mdl_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { - /* TODO: Implement process_md_delete_mdl_req */ + mcap_md_req *req; + struct mcap_mdl *mdl, *aux; + uint16_t mdlid; + gboolean notify; + GSList *l; + + if (len != sizeof(mcap_md_req)) { + mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, + MCAP_INVALID_PARAM_VALUE, MCAP_MDLID_RESERVED, NULL, 0); + return; + } + + req = (mcap_md_req *)cmd; + mdlid = ntohs(req->mdl); + if (mdlid == MCAP_ALL_MDLIDS) { + notify = FALSE; + g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify); + 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) { + mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL, + mdlid, NULL, 0); + 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) { + mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL, + mdlid, NULL, 0); + return; + } + mcl->mdls = g_slist_remove(mcl->mdls, mdl); + update_mcl_state(mcl); + notify = TRUE; + mcap_del_mdl(mdl, ¬ify); + +resp: + mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid, + NULL, 0); } static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) @@ -1240,11 +1383,65 @@ static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl, return close; } +static void restore_mdl(gpointer elem, gpointer data) +{ + struct mcap_mdl *mdl = elem; + + if (mdl->state == MDL_DELETING) { + if (mdl->dc) + mdl->state = MDL_CONNECTED; + else + mdl->state = MDL_CLOSED; + } else if (mdl->state == MDL_CLOSED) + mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data); +} + static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { - /* TODO: Implement process_md_delete_mdl_rsp */ - return TRUE; + struct mcap_mdl_op_cb *del = mcl->priv_data; + struct mcap_mdl *mdl = del->mdl; + mcap_mdl_notify_cb deleted_cb = del->cb.notify; + gpointer user_data = del->user_data; + mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd; + uint16_t mdlid = ntohs(cmdlast->mdl); + GError *gerr = NULL; + gboolean close = FALSE; + gboolean notify = FALSE; + + g_free(mcl->priv_data); + mcl->priv_data = NULL; + + close = check_err_rsp(mcl, cmd, len, sizeof(mcap_rsp), &gerr); + + g_free(mcl->lcmd); + mcl->lcmd = NULL; + mcl->req = MCL_AVAILABLE; + + if (gerr) { + if (mdl) + restore_mdl(mdl, NULL); + else + g_slist_foreach(mcl->mdls, restore_mdl, NULL); + deleted_cb(gerr, user_data); + g_error_free(gerr); + return close; + } + + if (mdlid == MCAP_ALL_MDLIDS) { + g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify); + g_slist_free(mcl->mdls); + mcl->mdls = NULL; + mcl->state = MCL_CONNECTED; + goto end; + } + + mcl->mdls = g_slist_remove(mcl->mdls, mdl); + update_mcl_state(mcl); + mcap_del_mdl(mdl, ¬ify); +end: + deleted_cb(gerr, user_data); + return close; } static void proc_response(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) diff --git a/health/mcap_lib.h b/health/mcap_lib.h index fbf97df..b9fc9a5 100644 --- a/health/mcap_lib.h +++ b/health/mcap_lib.h @@ -108,6 +108,14 @@ void mcap_reconnect_mdl(struct mcap_mdl *mdl, mcap_mdl_operation_cb reconnect_cb, gpointer user_data, GError **err); +void mcap_delete_all_mdls(struct mcap_mcl *mcl, + mcap_mdl_notify_cb delete_cb, + gpointer user_data, + GError **err); +void mcap_delete_mdl(struct mcap_mdl *mdl, + mcap_mdl_notify_cb delete_cb, + gpointer user_data, + GError **err); void mcap_connect_mdl(struct mcap_mdl *mdl, BtIOType BtType, uint16_t dcpsm, -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 13/16] Add functions for getting mdl properties 2010-07-28 8:03 ` [PATCH 12/16] Process MCAP process_md_delete_mdl " Jose Antonio Santos Cadenas @ 2010-07-28 8:07 ` Santiago Carot-Nemesio 2010-07-28 8:07 ` [PATCH 14/16] Response with invalid operation when an invalid request is received Santiago Carot-Nemesio 0 siblings, 1 reply; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:07 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- health/mcap.c | 16 ++++++++++++++++ health/mcap_lib.h | 3 +++ 2 files changed, 19 insertions(+), 0 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index 050a896..df75752 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -635,6 +635,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 -ENOTCONN; + + 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 mcap_free_mdls(struct mcap_mcl *mcl, gboolean save) { GSList *l; diff --git a/health/mcap_lib.h b/health/mcap_lib.h index b9fc9a5..b6286a1 100644 --- a/health/mcap_lib.h +++ b/health/mcap_lib.h @@ -127,6 +127,9 @@ void mcap_mdl_abort(struct mcap_mdl *mdl, gpointer user_data, GError **err); +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, -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 14/16] Response with invalid operation when an invalid request is received 2010-07-28 8:07 ` [PATCH 13/16] Add functions for getting mdl properties Santiago Carot-Nemesio @ 2010-07-28 8:07 ` Santiago Carot-Nemesio 2010-07-28 8:07 ` [PATCH 15/16] Add version and supported procedures values Santiago Carot-Nemesio 0 siblings, 1 reply; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:07 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- health/mcap.c | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/health/mcap.c b/health/mcap.c index df75752..f5f60ee 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -1164,7 +1164,15 @@ resp: static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { - /* TODO: Implements invalid_req_state */ + uint16_t mdlr; + + 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); + mcap_send_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr, NULL, 0); } /* Function used to process commands depending of MCL state */ -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 15/16] Add version and supported procedures values 2010-07-28 8:07 ` [PATCH 14/16] Response with invalid operation when an invalid request is received Santiago Carot-Nemesio @ 2010-07-28 8:07 ` Santiago Carot-Nemesio 2010-07-28 8:07 ` [PATCH 16/16] Add initial support for synchronization protocol Santiago Carot-Nemesio 0 siblings, 1 reply; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:07 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- health/mcap.h | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/health/mcap.h b/health/mcap.h index 1c72080..bb05969 100644 --- a/health/mcap.h +++ b/health/mcap.h @@ -31,6 +31,11 @@ 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 -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 16/16] Add initial support for synchronization protocol 2010-07-28 8:07 ` [PATCH 15/16] Add version and supported procedures values Santiago Carot-Nemesio @ 2010-07-28 8:07 ` Santiago Carot-Nemesio 0 siblings, 0 replies; 18+ messages in thread From: Santiago Carot-Nemesio @ 2010-07-28 8:07 UTC (permalink / raw) To: linux-bluetooth; +Cc: Santiago Carot-Nemesio --- Makefile.am | 3 +- health/mcap.c | 2 +- health/mcap.h | 38 +++++++++++++++++++++++++++++++ health/mcap_sync.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 health/mcap_sync.c diff --git a/Makefile.am b/Makefile.am index c8bd62a..084879b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -171,7 +171,8 @@ endif if MCAP mcap_sources += health/mcap_lib.h health/mcap_internal.h \ - health/mcap.h health/mcap.c + health/mcap.h health/mcap.c \ + health/mcap_sync.c endif builtin_modules += hciops diff --git a/health/mcap.c b/health/mcap.c index f5f60ee..f00a484 100644 --- a/health/mcap.c +++ b/health/mcap.c @@ -1513,7 +1513,7 @@ 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) { - /* TODO: proc_sync_cmd(mcl, cmd, len);*/ + proc_sync_cmd(mcl, cmd, len); return; } diff --git a/health/mcap.h b/health/mcap.h index bb05969..9b95473 100644 --- a/health/mcap.h +++ b/health/mcap.h @@ -111,6 +111,44 @@ typedef struct { uint16_t mdl; } __attribute__ ((packed)) mcap_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 } diff --git a/health/mcap_sync.c b/health/mcap_sync.c new file mode 100644 index 0000000..569a40a --- /dev/null +++ b/health/mcap_sync.c @@ -0,0 +1,62 @@ +/* + * + * 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 <stdint.h> +#include <netinet/in.h> + +#include "log.h" + +#include "mcap.h" +#include "mcap_lib.h" +#include "mcap_internal.h" + +void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) +{ + switch (cmd[0]) { + case MCAP_MD_SYNC_CAP_REQ: + DBG("TODO: received MCAP_MD_SYNC_CAP_REQ: %d", + MCAP_MD_SYNC_CAP_REQ); + /* Not implemented yet. Reply with unsupported request */ + break; + case MCAP_MD_SYNC_CAP_RSP: + DBG("TODO: received MCAP_MD_SYNC_CAP_RSP: %d", + MCAP_MD_SYNC_CAP_RSP); + break; + case MCAP_MD_SYNC_SET_REQ: + DBG("TODO: received MCAP_MD_SYNC_SET_REQ: %d", + MCAP_MD_SYNC_SET_REQ); + /* Not implemented yet. Reply with unsupported request */ + break; + case MCAP_MD_SYNC_SET_RSP: + DBG("TODO: received MCAP_MD_SYNC_SET_RSP: %d", + MCAP_MD_SYNC_SET_RSP); + break; + case MCAP_MD_SYNC_INFO_IND: + DBG("TODO: received MCAP_MD_SYNC_INFO_IND :%d", + MCAP_MD_SYNC_INFO_IND); + break; + } +} -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: MCAP patches 2010-07-28 8:00 MCAP patches Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 01/16] Initial support for MCAP Santiago Carot-Nemesio @ 2010-08-04 9:02 ` José Antonio Santos Cadenas 1 sibling, 0 replies; 18+ messages in thread From: José Antonio Santos Cadenas @ 2010-08-04 9:02 UTC (permalink / raw) To: Santiago Carot-Nemesio; +Cc: linux-bluetooth Hi all, Wednesday 28 July 2010 10:00:09 Santiago Carot-Nemesio wrote: > Hello, > Next are the patches that we have prepared for MCAP. > Git can be cloned from git://gitorious.org/bluez-mcap-hdp/mcap-hdp.git > > Regards. Any comments about this patches? Regards. ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2010-08-04 9:02 UTC | newest] Thread overview: 18+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-07-28 8:00 MCAP patches Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 01/16] Initial support for MCAP Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 02/16] Add MCAP instance management Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 03/16] Receive MCAP mcl connections from remote devices Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 04/16] Added function for MCAP control channel (MCL) management Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 05/16] Prepare FSM functions for processing comands Santiago Carot-Nemesio 2010-07-28 8:00 ` [PATCH 06/16] Send MCAP request mcap_md_create_mdl_req Santiago Carot-Nemesio 2010-07-28 8:03 ` [PATCH 07/16] Process " Jose Antonio Santos Cadenas 2010-07-28 8:03 ` [PATCH 08/16] Process MCAP response mcap_md_create_mdl_rsp Jose Antonio Santos Cadenas 2010-07-28 8:03 ` [PATCH 09/16] Implement connection of MCAP data links (MDL's) Jose Antonio Santos Cadenas 2010-07-28 8:03 ` [PATCH 10/16] Process MCAP process_md_abort_mdl request and response commands Jose Antonio Santos Cadenas 2010-07-28 8:03 ` [PATCH 11/16] Process MCAP process_md_reconnect_mdl " Jose Antonio Santos Cadenas 2010-07-28 8:03 ` [PATCH 12/16] Process MCAP process_md_delete_mdl " Jose Antonio Santos Cadenas 2010-07-28 8:07 ` [PATCH 13/16] Add functions for getting mdl properties Santiago Carot-Nemesio 2010-07-28 8:07 ` [PATCH 14/16] Response with invalid operation when an invalid request is received Santiago Carot-Nemesio 2010-07-28 8:07 ` [PATCH 15/16] Add version and supported procedures values Santiago Carot-Nemesio 2010-07-28 8:07 ` [PATCH 16/16] Add initial support for synchronization protocol Santiago Carot-Nemesio 2010-08-04 9:02 ` MCAP patches José Antonio Santos Cadenas
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).