All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 BlueZ 1/3] unit/test-avrcp: Add /TP/RCR/BV-02-C test
@ 2014-06-05  8:07 Luiz Augusto von Dentz
  2014-06-05  8:07 ` [PATCH v2 BlueZ 2/3] unit/test-avrcp: Add /TP/RCR/BV-04-C test Luiz Augusto von Dentz
  2014-06-05  8:07 ` [PATCH v2 BlueZ 3/3] android/avrcp-lib: Add fragmentation support Luiz Augusto von Dentz
  0 siblings, 2 replies; 3+ messages in thread
From: Luiz Augusto von Dentz @ 2014-06-05  8:07 UTC (permalink / raw)
  To: linux-bluetooth

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

To verify that the TG can handle fragmentation correctly.
---
v2: Fix not copying from offset.

 unit/test-avrcp.c | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index c41f2e6..eddce41 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -46,6 +46,7 @@
 struct test_pdu {
 	bool valid;
 	bool fragmented;
+	bool continuing;
 	bool browse;
 	const uint8_t *data;
 	size_t size;
@@ -93,6 +94,14 @@ struct context {
 		.size = sizeof(data(args)),			\
 	}
 
+#define cont_pdu(args...)					\
+	{							\
+		.valid = true,					\
+		.continuing = true,				\
+		.data = data(args),				\
+		.size = sizeof(data(args)),			\
+	}
+
 #define define_test(name, function, args...)				\
 	do {								\
 		const struct test_pdu pdus[] = {			\
@@ -195,7 +204,8 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
 	if (g_test_verbose())
 		util_hexdump('>', buf, len, test_debug, "AVRCP: ");
 
-	g_assert_cmpint(len, ==, pdu->size);
+	if (!pdu->continuing)
+		g_assert_cmpint(len, ==, pdu->size);
 
 	g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
 
@@ -486,9 +496,20 @@ static int get_element_attributes(struct avrcp *session, uint8_t transaction,
 					uint64_t uid, uint8_t number,
 					uint32_t *attrs, void *user_data)
 {
+	struct context *context = user_data;
+
 	DBG("");
 
-	avrcp_get_element_attrs_rsp(session, transaction, NULL, 0);
+	if (g_str_equal(context->data->test_name, "/TP/RCR/BV-02-C")) {
+		uint8_t params[1024];
+
+		memset(params, 0x00, sizeof(params) / 2);
+		memset(params + (sizeof(params) / 2), 0xff, sizeof(params) / 2);
+
+		avrcp_get_element_attrs_rsp(session, transaction, params,
+							sizeof(params));
+	} else
+		avrcp_get_element_attrs_rsp(session, transaction, NULL, 0);
 
 	return -EAGAIN;
 }
@@ -1623,5 +1644,27 @@ int main(int argc, char *argv[])
 				0x00, 0x19, 0x58, AVRCP_SET_ABSOLUTE_VOLUME,
 				0x00, 0x00, 0x01, 0x00));
 
+	/* Request continuing response - TG */
+	define_test("/TP/RCR/BV-02-C", test_server,
+			raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+			cont_pdu(0x02, 0x11, 0x0e, 0x0c, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x01, 0x01, 0xf9),
+			raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_REQUEST_CONTINUING,
+				0x00, 0x00, 0x01, AVRCP_GET_ELEMENT_ATTRIBUTES),
+			cont_pdu(0x02, 0x11, 0x0e, 0x0c, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x02, 0x01, 0xf9),
+			raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_REQUEST_CONTINUING,
+				0x00, 0x00, 0x01, AVRCP_GET_ELEMENT_ATTRIBUTES),
+			cont_pdu(0x02, 0x11, 0x0e, 0x0c, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x03, 0x00, 0x0e));
+
 	return g_test_run();
 }
-- 
1.9.3


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

* [PATCH v2 BlueZ 2/3] unit/test-avrcp: Add /TP/RCR/BV-04-C test
  2014-06-05  8:07 [PATCH v2 BlueZ 1/3] unit/test-avrcp: Add /TP/RCR/BV-02-C test Luiz Augusto von Dentz
@ 2014-06-05  8:07 ` Luiz Augusto von Dentz
  2014-06-05  8:07 ` [PATCH v2 BlueZ 3/3] android/avrcp-lib: Add fragmentation support Luiz Augusto von Dentz
  1 sibling, 0 replies; 3+ messages in thread
From: Luiz Augusto von Dentz @ 2014-06-05  8:07 UTC (permalink / raw)
  To: linux-bluetooth

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

To verify the TG can accept abort fragmentation correctly.
---
 unit/test-avrcp.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index eddce41..e8cf34a 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -500,7 +500,7 @@ static int get_element_attributes(struct avrcp *session, uint8_t transaction,
 
 	DBG("");
 
-	if (g_str_equal(context->data->test_name, "/TP/RCR/BV-02-C")) {
+	if (g_str_has_prefix(context->data->test_name, "/TP/RCR")) {
 		uint8_t params[1024];
 
 		memset(params, 0x00, sizeof(params) / 2);
@@ -1666,5 +1666,21 @@ int main(int argc, char *argv[])
 				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
 				0x03, 0x00, 0x0e));
 
+	/* Abort continuing response - TG */
+	define_test("/TP/RCR/BV-04-C", test_server,
+			raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
+			cont_pdu(0x02, 0x11, 0x0e, 0x0c, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_GET_ELEMENT_ATTRIBUTES,
+				0x01, 0x01, 0xf9),
+			raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_ABORT_CONTINUING,
+				0x00, 0x00, 0x01, AVRCP_GET_ELEMENT_ATTRIBUTES),
+			raw_pdu(0x02, 0x11, 0x0e, 0x09, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_ABORT_CONTINUING,
+				0x00, 0x00, 0x00));
+
 	return g_test_run();
 }
-- 
1.9.3


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

* [PATCH v2 BlueZ 3/3] android/avrcp-lib: Add fragmentation support
  2014-06-05  8:07 [PATCH v2 BlueZ 1/3] unit/test-avrcp: Add /TP/RCR/BV-02-C test Luiz Augusto von Dentz
  2014-06-05  8:07 ` [PATCH v2 BlueZ 2/3] unit/test-avrcp: Add /TP/RCR/BV-04-C test Luiz Augusto von Dentz
@ 2014-06-05  8:07 ` Luiz Augusto von Dentz
  1 sibling, 0 replies; 3+ messages in thread
From: Luiz Augusto von Dentz @ 2014-06-05  8:07 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds handling for fragmentation if the PDU cannot fit into a AV/C
frame which can be up to 512 bytes or less depending on the L2CAP MTU
negotiated.
---
 android/avrcp-lib.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 185 insertions(+), 22 deletions(-)

diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 036867e..b1d281b 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -96,6 +96,11 @@ struct avrcp_browsing_handler {
 			uint16_t params_len, uint8_t *params, void *user_data);
 };
 
+struct avrcp_continuing {
+	uint8_t pdu_id;
+	struct iovec pdu;
+};
+
 struct avrcp {
 	struct avctp *conn;
 	struct avrcp_player *player;
@@ -103,6 +108,9 @@ struct avrcp {
 	const struct avrcp_control_handler *control_handlers;
 	void *control_data;
 	unsigned int control_id;
+	uint16_t control_mtu;
+
+	struct avrcp_continuing *continuing;
 
 	const struct avrcp_passthrough_handler *passthrough_handlers;
 	void *passthrough_data;
@@ -135,6 +143,12 @@ static inline void hton24(uint8_t dst[3], uint32_t src)
 	dst[2] = (src & 0x0000ff);
 }
 
+static void continuing_free(struct avrcp_continuing *continuing)
+{
+	g_free(continuing->pdu.iov_base);
+	g_free(continuing);
+}
+
 void avrcp_shutdown(struct avrcp *session)
 {
 	if (session->conn) {
@@ -153,6 +167,9 @@ void avrcp_shutdown(struct avrcp *session)
 	if (session->destroy)
 		session->destroy(session->destroy_data);
 
+	if (session->continuing)
+		continuing_free(session->continuing);
+
 	g_free(session->player);
 	g_free(session);
 }
@@ -340,6 +357,14 @@ struct avrcp *avrcp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
 							AVC_OP_VENDORDEP,
 							handle_vendordep_pdu,
 							session);
+	session->control_mtu = omtu;
+
+	/*
+	 * 27.1.2 AV/C Command Frame
+	 * An AV/C command frame contains up to 512 octets of data
+	 */
+	if (session->control_mtu > 512)
+		session->control_mtu = 512;
 
 	avctp_set_destroy_cb(session->conn, disconnect_cb, session);
 
@@ -751,6 +776,158 @@ static ssize_t set_addressed(struct avrcp *session, uint8_t transaction,
 							player->user_data);
 }
 
+static void continuing_new(struct avrcp *session, uint8_t pdu_id,
+					const struct iovec *iov, int iov_cnt,
+					size_t offset)
+{
+	struct avrcp_continuing *continuing;
+	int i;
+	size_t len = 0;
+
+	continuing = g_new0(struct avrcp_continuing, 1);
+	continuing->pdu_id = pdu_id;
+
+	for (i = 0; i < iov_cnt; i++) {
+		if (i == 0 && offset) {
+			len += iov[i].iov_len - offset;
+			continue;
+		}
+
+		len += iov[i].iov_len;
+	}
+
+	continuing->pdu.iov_base = g_malloc0(len);
+
+	DBG("len %zu", len);
+
+	for (i = 0; i < iov_cnt; i++) {
+		if (i == 0 && offset) {
+			memcpy(continuing->pdu.iov_base,
+						iov[i].iov_base + offset,
+						iov[i].iov_len - offset);
+			continuing->pdu.iov_len += iov[i].iov_len - offset;
+			continue;
+		}
+
+		memcpy(continuing->pdu.iov_base + continuing->pdu.iov_len,
+					iov[i].iov_base, iov[i].iov_len);
+		continuing->pdu.iov_len += iov[i].iov_len;
+	}
+
+	session->continuing = continuing;
+}
+
+static int avrcp_send_internal(struct avrcp *session, uint8_t transaction,
+					uint8_t code, uint8_t subunit,
+					uint8_t pdu_id, uint8_t type,
+					const struct iovec *iov, int iov_cnt)
+{
+	struct iovec pdu[iov_cnt + 1];
+	struct avrcp_header hdr;
+	int i;
+
+	/*
+	 * If a receiver receives a start fragment or non-fragmented AVRCP
+	 * Specific AV/C message when it already has an incomplete fragment
+	 * from that sender then the receiver shall consider the first PDU
+	 * aborted.
+	 */
+	if (session->continuing) {
+		continuing_free(session->continuing);
+		session->continuing = NULL;
+	}
+
+	memset(&hdr, 0, sizeof(hdr));
+
+	pdu[0].iov_base = &hdr;
+	pdu[0].iov_len = sizeof(hdr);
+
+	hdr.packet_type = type;
+
+	for (i = 0; i < iov_cnt; i++) {
+		pdu[i + 1].iov_base = iov[i].iov_base;
+
+		if (pdu[0].iov_len + hdr.params_len + iov[i].iov_len <=
+							session->control_mtu) {
+			pdu[i + 1].iov_len = iov[i].iov_len;
+			hdr.params_len += iov[i].iov_len;
+			if (hdr.packet_type != AVRCP_PACKET_TYPE_SINGLE)
+				hdr.packet_type = AVRCP_PACKET_TYPE_END;
+			continue;
+		}
+
+		/*
+		 * Only send what can fit and store the remaining in the
+		 * continuing iovec
+		 */
+		pdu[i + 1].iov_len = session->control_mtu -
+					(pdu[0].iov_len + hdr.params_len);
+		hdr.params_len += pdu[i + 1].iov_len;
+
+		continuing_new(session, pdu_id, &iov[i], iov_cnt - i,
+							pdu[i + 1].iov_len);
+
+		hdr.packet_type = hdr.packet_type != AVRCP_PACKET_TYPE_SINGLE ?
+						AVRCP_PACKET_TYPE_CONTINUING :
+						AVRCP_PACKET_TYPE_START;
+		break;
+	}
+
+	hton24(hdr.company_id, IEEEID_BTSIG);
+	hdr.pdu_id = pdu_id;
+	hdr.params_len = htons(hdr.params_len);
+
+	return avctp_send_vendor(session->conn, transaction, code, subunit,
+							pdu, iov_cnt + 1);
+}
+
+static ssize_t request_continuing(struct avrcp *session, uint8_t transaction,
+					uint16_t params_len, uint8_t *params,
+					void *user_data)
+{
+	struct iovec iov;
+	int err;
+
+	DBG("");
+
+	if (!params || params_len != 1 || !session->continuing ||
+				session->continuing->pdu_id != params[0])
+		return -EINVAL;
+
+	iov.iov_base = session->continuing->pdu.iov_base;
+	iov.iov_len = session->continuing->pdu.iov_len;
+
+	DBG("len %zu", iov.iov_len);
+
+	session->continuing->pdu.iov_base = NULL;
+
+	err = avrcp_send_internal(session, transaction, AVC_CTYPE_STABLE,
+					AVC_SUBUNIT_PANEL, params[0],
+					AVRCP_PACKET_TYPE_CONTINUING, &iov, 1);
+
+	g_free(iov.iov_base);
+
+	if (err < 0)
+		return -EINVAL;
+
+	return -EAGAIN;
+}
+
+static ssize_t abort_continuing(struct avrcp *session, uint8_t transaction,
+					uint16_t params_len, uint8_t *params,
+					void *user_data)
+{
+	DBG("");
+
+	if (!params || params_len != 1 || !session->continuing)
+		return -EINVAL;
+
+	continuing_free(session->continuing);
+	session->continuing = NULL;
+
+	return 0;
+}
+
 static const struct avrcp_control_handler player_handlers[] = {
 		{ AVRCP_GET_CAPABILITIES,
 					AVC_CTYPE_STATUS, AVC_CTYPE_STABLE,
@@ -788,6 +965,12 @@ static const struct avrcp_control_handler player_handlers[] = {
 		{ AVRCP_SET_ADDRESSED_PLAYER,
 					AVC_CTYPE_CONTROL, AVC_CTYPE_STABLE,
 					set_addressed },
+		{ AVRCP_REQUEST_CONTINUING,
+					AVC_CTYPE_CONTROL, AVC_CTYPE_STABLE,
+					request_continuing },
+		{ AVRCP_ABORT_CONTINUING,
+					AVC_CTYPE_CONTROL, AVC_CTYPE_ACCEPTED,
+					abort_continuing },
 		{ },
 };
 
@@ -1049,28 +1232,8 @@ int avrcp_send(struct avrcp *session, uint8_t transaction, uint8_t code,
 					uint8_t subunit, uint8_t pdu_id,
 					const struct iovec *iov, int iov_cnt)
 {
-	struct iovec pdu[iov_cnt + 1];
-	struct avrcp_header hdr;
-	int i;
-
-	memset(&hdr, 0, sizeof(hdr));
-
-	pdu[0].iov_base = &hdr;
-	pdu[0].iov_len = sizeof(hdr);
-
-	for (i = 0; i < iov_cnt; i++) {
-		pdu[i + 1].iov_base = iov[i].iov_base;
-		pdu[i + 1].iov_len = iov[i].iov_len;
-		hdr.params_len += iov[i].iov_len;
-	}
-
-	hton24(hdr.company_id, IEEEID_BTSIG);
-	hdr.pdu_id = pdu_id;
-	hdr.packet_type = AVRCP_PACKET_TYPE_SINGLE;
-	hdr.params_len = htons(hdr.params_len);
-
-	return avctp_send_vendor(session->conn, transaction, code, subunit,
-							pdu, iov_cnt + 1);
+	return avrcp_send_internal(session, transaction, code, subunit, pdu_id,
+					AVRCP_PACKET_TYPE_SINGLE, iov, iov_cnt);
 }
 
 static int status2errno(uint8_t status)
-- 
1.9.3


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

end of thread, other threads:[~2014-06-05  8:07 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-05  8:07 [PATCH v2 BlueZ 1/3] unit/test-avrcp: Add /TP/RCR/BV-02-C test Luiz Augusto von Dentz
2014-06-05  8:07 ` [PATCH v2 BlueZ 2/3] unit/test-avrcp: Add /TP/RCR/BV-04-C test Luiz Augusto von Dentz
2014-06-05  8:07 ` [PATCH v2 BlueZ 3/3] android/avrcp-lib: Add fragmentation support Luiz Augusto von Dentz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.