Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v2 2/2] android/hal: Verify command status response before processing
From: Szymon Janc @ 2013-11-18 12:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1384779520-2104-1-git-send-email-szymon.janc@tieto.com>

This makes HAL IPC code verify error reply before processing it. It
also verify if success status was reported according to IPC spec.
---
 android/hal-ipc.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/android/hal-ipc.c b/android/hal-ipc.c
index 026e245..5155e04 100644
--- a/android/hal-ipc.c
+++ b/android/hal-ipc.c
@@ -367,6 +367,17 @@ int hal_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param,
 
 	if (cmd.opcode == HAL_OP_STATUS) {
 		struct hal_status *s = rsp;
+
+		if (sizeof(*s) != cmd.len) {
+			error("Invalid status length, aborting");
+			exit(EXIT_FAILURE);
+		}
+
+		if (s->code == HAL_STATUS_SUCCESS) {
+			error("Invalid success status response, aborting");
+			exit(EXIT_FAILURE);
+		}
+
 		return s->code;
 	}
 
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 1/2] android: Improve IPC helper to not send invalid status response
From: Szymon Janc @ 2013-11-18 12:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This fix issue with sending invalid success response from several
places where ipc_send_rsp was used for reporting success. Instead of
using using ipc_send for success response, make helper handle that.
---
V2: fixed hardcoded service id in ipc_send_rsp

 android/a2dp.c      |  2 +-
 android/bluetooth.c |  2 +-
 android/hidhost.c   |  2 +-
 android/ipc.c       |  7 ++++++-
 android/ipc.h       |  2 +-
 android/main.c      | 12 ++++++++----
 android/pan.c       |  2 +-
 android/socket.c    |  2 +-
 8 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 936c28e..bb55e41 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -226,7 +226,7 @@ void bt_a2dp_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 		break;
 	}
 
-	ipc_send_rsp(sk, HAL_SERVICE_ID_A2DP, status);
+	ipc_send_rsp(sk, HAL_SERVICE_ID_A2DP, opcode, status);
 }
 
 static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 5c5c61e..7dc2ec3 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -2268,7 +2268,7 @@ void bt_bluetooth_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 error:
 	error("Error handling command 0x%02x status %u", opcode, status);
 
-	ipc_send_rsp(sk, HAL_SERVICE_ID_BLUETOOTH, status);
+	ipc_send_rsp(sk, HAL_SERVICE_ID_BLUETOOTH, opcode, status);
 }
 
 bool bt_bluetooth_register(int sk)
diff --git a/android/hidhost.c b/android/hidhost.c
index f5a607c..842b8ad 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -1109,7 +1109,7 @@ void bt_hid_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 		break;
 	}
 
-	ipc_send_rsp(sk, HAL_SERVICE_ID_HIDHOST, status);
+	ipc_send_rsp(sk, HAL_SERVICE_ID_HIDHOST, opcode, status);
 }
 
 static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
diff --git a/android/ipc.c b/android/ipc.c
index 729f157..8467b28 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -80,10 +80,15 @@ void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
 	}
 }
 
-void ipc_send_rsp(int sk, uint8_t service_id, uint8_t status)
+void ipc_send_rsp(int sk, uint8_t service_id, uint8_t opcode, uint8_t status)
 {
 	struct hal_status s;
 
+	if (status == HAL_STATUS_SUCCESS) {
+		ipc_send(sk, service_id, opcode, 0, NULL, -1);
+		return;
+	}
+
 	s.code = status;
 
 	ipc_send(sk, service_id, HAL_OP_STATUS, sizeof(s), &s, -1);
diff --git a/android/ipc.h b/android/ipc.h
index cf0f3d6..ad4a2d2 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -23,4 +23,4 @@
 
 void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
 							void *param, int fd);
-void ipc_send_rsp(int sk, uint8_t service_id, uint8_t status);
+void ipc_send_rsp(int sk, uint8_t service_id, uint8_t opcode, uint8_t status);
diff --git a/android/main.c b/android/main.c
index a4f5e84..c9733f3 100644
--- a/android/main.c
+++ b/android/main.c
@@ -122,7 +122,8 @@ static void service_register(void *buf, uint16_t len)
 	return;
 failed:
 	ipc_send_rsp(g_io_channel_unix_get_fd(hal_cmd_io),
-				HAL_SERVICE_ID_CORE, HAL_STATUS_FAILED);
+				HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+				HAL_STATUS_FAILED);
 }
 
 static void service_unregister(void *buf, uint16_t len)
@@ -164,7 +165,8 @@ static void service_unregister(void *buf, uint16_t len)
 	return;
 failed:
 	ipc_send_rsp(g_io_channel_unix_get_fd(hal_cmd_io),
-				HAL_SERVICE_ID_CORE, HAL_STATUS_FAILED);
+				HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
+				HAL_STATUS_FAILED);
 }
 
 static void handle_service_core(uint8_t opcode, void *buf, uint16_t len)
@@ -178,7 +180,8 @@ static void handle_service_core(uint8_t opcode, void *buf, uint16_t len)
 		break;
 	default:
 		ipc_send_rsp(g_io_channel_unix_get_fd(hal_cmd_io),
-				HAL_SERVICE_ID_CORE, HAL_STATUS_FAILED);
+						HAL_SERVICE_ID_CORE, opcode,
+						HAL_STATUS_FAILED);
 		break;
 	}
 }
@@ -274,7 +277,8 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
 		bt_pan_handle_cmd(fd, msg->opcode, msg->payload, msg->len);
 		break;
 	default:
-		ipc_send_rsp(fd, msg->service_id, HAL_STATUS_FAILED);
+		ipc_send_rsp(fd, msg->service_id, msg->opcode,
+							HAL_STATUS_FAILED);
 		break;
 	}
 
diff --git a/android/pan.c b/android/pan.c
index 46b3700..2a11f46 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -87,7 +87,7 @@ void bt_pan_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 		break;
 	}
 
-	ipc_send_rsp(sk, HAL_SERVICE_ID_PAN, status);
+	ipc_send_rsp(sk, HAL_SERVICE_ID_PAN, opcode, status);
 }
 
 bool bt_pan_register(int sk, const bdaddr_t *addr)
diff --git a/android/socket.c b/android/socket.c
index e580036..04bb7d1 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -75,7 +75,7 @@ void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 		break;
 	}
 
-	ipc_send_rsp(sk, HAL_SERVICE_ID_SOCK, HAL_STATUS_FAILED);
+	ipc_send_rsp(sk, HAL_SERVICE_ID_SOCK, opcode, HAL_STATUS_FAILED);
 }
 
 bool bt_socket_register(int sk, const bdaddr_t *addr)
-- 
1.8.4.2


^ permalink raw reply related

* Re: BUG: unable to handle kernel paging request at 00000015832a8e23 RIP  [<ffffffff81a57c30>] rfcomm_sock_getsockopt+0x140/0x240
From: Sander Eikelenboom @ 2013-11-18 12:32 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Gustavo F. Padovan, linux-bluetooth@vger.kernel.org development
In-Reply-To: <344AB0A2-9E39-4294-A119-887D2FAA2036@holtmann.org>

=0D=0ASunday, November 17, 2013, 11:57:40 PM, you wrote:

> Hi Sander,

>> This 3.13 merge window seems to have introduced the following bluetooth =
regression for me:
>>=20
>> [   62.040810] BUG: unable to handle kernel paging request at 0000001583=
2a8e23
>> [   62.049196] IP: [<ffffffff81a57c30>] rfcomm_sock_getsockopt+0x140/0x2=
40
>> [   62.057800] PGD 0=20
>> [   62.064574] Oops: 0000 [#1] PREEMPT SMP=20
>> [   62.070653] Modules linked in:
>> [   62.076596] CPU: 4 PID: 5575 Comm: bluetoothd Not tainted 3.12.0-mw-2=
0131117+ #1
>> [   62.082708] Hardware name: MSI MS-7640/890FXA-GD70 (MS-7640)  , BIOS =
V1.8B1 09/13/2010
>> [   62.088827] task: ffff88005863a180 ti: ffff880057688000 task.ti: ffff=
880057688000
>> [   62.095020] RIP: e030:[<ffffffff81a57c30>]  [<ffffffff81a57c30>] rfco=
mm_sock_getsockopt+0x140/0x240
>> [   62.101372] RSP: e02b:ffff880057689ec8  EFLAGS: 00010246
>> [   62.107668] RAX: 00000015832a8e23 RBX: 0000000000000003 RCX: 00007fff=
610ca0e8
>> [   62.113957] RDX: 0000000000000003 RSI: 0000000000000012 RDI: ffff8800=
572a9e00
>> [   62.120174] RBP: ffff880057689f18 R08: 00007fff610ca0ec R09: 00007fff=
610ca360
>> [   62.126481] R10: 00007fff610ca0e8 R11: 0000000000000202 R12: ffff8800=
569c3000
>> [   62.132872] R13: 00007fff610ca0e8 R14: 0000000000000000 R15: 00007fff=
610ca0ec
>> [   62.139187] FS:  00007f0d0b348720(0000) GS:ffff88005f700000(0000) knl=
GS:0000000000000000
>> [   62.145551] CS:  e033 DS: 0000 ES: 0000 CR0: 000000008005003b
>> [   62.151919] CR2: 00000015832a8e23 CR3: 0000000056f53000 CR4: 00000000=
00000660
>> [   62.158338] Stack:
>> [   62.164798]  ffff880057689f18 ffffffff81a5799f 0015832a8e23001f ffff8=
80057689f40
>> [   62.171410]  ffff880057689f44 ffff8800572a9e00 0000000000000012 00000=
00000000003
>> [   62.178096]  0000000000000000 00007fff610ca0e8 ffff880057689f78 fffff=
fff81905bc2
>> [   62.184781] Call Trace:
>> [   62.191344]  [<ffffffff81a5799f>] ? rfcomm_sock_setsockopt+0x5f/0x1b0
>> [   62.197978]  [<ffffffff81905bc2>] SyS_getsockopt+0x62/0xb0
>> [   62.204645]  [<ffffffff81a8aa79>] system_call_fastpath+0x16/0x1b
>> [   62.211366] Code: 84 24 40 04 00 00 4c 89 e9 83 e0 01 e8 ea 0a 9d ff =
85 c0 75 b5 45 31 f6 e9 42 ff ff ff 66 0f 1f 44 00 00 49 8b 84 24 50 04 00 =
00 <48> 8b 00 48 89 45 b8 e8 04 e7 6f ff 4c 89 f8 e8 2c fa 9c ff 85=20
>> [   62.225815] RIP  [<ffffffff81a57c30>] rfcomm_sock_getsockopt+0x140/0x=
240
>> [   62.232986]  RSP <ffff880057689ec8>
>> [   62.240128] CR2: 00000015832a8e23
>> [   62.247221] ---[ end trace 88f75f0c791ac25b ]---
>>=20
>> My bluetooth device is USB stick:
>> Bus 004 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth =
Dongle (HCI mode)

> I assume this is the same one we already fixed. Patch is on its way into =
Linus=92 tree. You can check bluetooth.git tree since that has this patch i=
ncluded.

Yes you are right !
Thx and sorry for the noise ..

--
Sander



> Regards

> Marcel

^ permalink raw reply

* Re: [PATCH BlueZ 1/5] audio/AVDTP: Remove unused code
From: Johan Hedberg @ 2013-11-18 12:11 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1384775415-10159-1-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Mon, Nov 18, 2013, Luiz Augusto von Dentz wrote:
> ---
>  profiles/audio/avdtp.c | 20 --------------------
>  profiles/audio/avdtp.h |  8 --------
>  2 files changed, 28 deletions(-)

All five patches have been applied. Thanks.

Johan

^ permalink raw reply

* [PATCH BlueZ 5/5] audio/AVDTP: Remove unused avdtp_set_device_disconnect
From: Luiz Augusto von Dentz @ 2013-11-18 11:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384775415-10159-1-git-send-email-luiz.dentz@gmail.com>

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

---
 profiles/audio/avdtp.c | 13 -------------
 profiles/audio/avdtp.h |  2 --
 2 files changed, 15 deletions(-)

diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
index de31e12..b7a7d9c 100644
--- a/profiles/audio/avdtp.c
+++ b/profiles/audio/avdtp.c
@@ -394,9 +394,6 @@ struct avdtp {
 
 	avdtp_session_state_t state;
 
-	/* True if the entire device is being disconnected */
-	gboolean device_disconnect;
-
 	guint auth_id;
 
 	GIOChannel *io;
@@ -1200,11 +1197,6 @@ static void set_disconnect_timer(struct avdtp *session)
 	if (session->dc_timer)
 		remove_disconnect_timer(session);
 
-	if (session->device_disconnect) {
-		session->dc_timer = g_idle_add(disconnect_timeout, session);
-		return;
-	}
-
 	session->dc_timer = g_timeout_add_seconds(DISCONNECT_TIMEOUT,
 						disconnect_timeout,
 						session);
@@ -3841,11 +3833,6 @@ gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream)
 	return g_slist_find(session->streams, stream) ? TRUE : FALSE;
 }
 
-void avdtp_set_device_disconnect(struct avdtp *session, gboolean dev_dc)
-{
-	session->device_disconnect = dev_dc;
-}
-
 unsigned int avdtp_add_state_cb(struct btd_device *dev,
 				avdtp_session_state_cb cb, void *user_data)
 {
diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h
index 3c30d78..390c154 100644
--- a/profiles/audio/avdtp.h
+++ b/profiles/audio/avdtp.h
@@ -293,5 +293,3 @@ int avdtp_error_posix_errno(struct avdtp_error *err);
 
 struct btd_adapter *avdtp_get_adapter(struct avdtp *session);
 struct btd_device *avdtp_get_device(struct avdtp *session);
-
-void avdtp_set_device_disconnect(struct avdtp *session, gboolean dev_dc);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ 4/5] audio/sink: Remove shutdown parameter from sink_disconnect
From: Luiz Augusto von Dentz @ 2013-11-18 11:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384775415-10159-1-git-send-email-luiz.dentz@gmail.com>

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

This parameter is always false so it never do anything.
---
 profiles/audio/a2dp.c | 2 +-
 profiles/audio/sink.c | 5 +----
 profiles/audio/sink.h | 2 +-
 3 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
index 95ffa12..29a1593 100644
--- a/profiles/audio/a2dp.c
+++ b/profiles/audio/a2dp.c
@@ -1919,7 +1919,7 @@ static int a2dp_sink_disconnect(struct btd_service *service)
 
 	DBG("path %s", path);
 
-	return sink_disconnect(service, FALSE);
+	return sink_disconnect(service);
 }
 
 static int a2dp_source_server_probe(struct btd_profile *p,
diff --git a/profiles/audio/sink.c b/profiles/audio/sink.c
index 400af06..4f39622 100644
--- a/profiles/audio/sink.c
+++ b/profiles/audio/sink.c
@@ -388,16 +388,13 @@ gboolean sink_new_stream(struct btd_service *service, struct avdtp *session,
 	return TRUE;
 }
 
-int sink_disconnect(struct btd_service *service, gboolean shutdown)
+int sink_disconnect(struct btd_service *service)
 {
 	struct sink *sink = btd_service_get_user_data(service);
 
 	if (!sink->session)
 		return -ENOTCONN;
 
-	if (shutdown)
-		avdtp_set_device_disconnect(sink->session, TRUE);
-
 	/* cancel pending connect */
 	if (sink->connect_id > 0) {
 		a2dp_cancel(sink->connect_id);
diff --git a/profiles/audio/sink.h b/profiles/audio/sink.h
index 904a33d..93c62a2 100644
--- a/profiles/audio/sink.h
+++ b/profiles/audio/sink.h
@@ -47,4 +47,4 @@ int sink_connect(struct btd_service *service);
 gboolean sink_new_stream(struct btd_service *service, struct avdtp *session,
 				struct avdtp_stream *stream);
 gboolean sink_setup_stream(struct btd_service *service, struct avdtp *session);
-int sink_disconnect(struct btd_service *service, gboolean shutdown);
+int sink_disconnect(struct btd_service *service);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ 3/5] audio/source: Remove shutdown parameter from source_disconnect
From: Luiz Augusto von Dentz @ 2013-11-18 11:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384775415-10159-1-git-send-email-luiz.dentz@gmail.com>

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

This parameter is always false so it never do anything.
---
 profiles/audio/a2dp.c   | 2 +-
 profiles/audio/source.c | 5 +----
 profiles/audio/source.h | 2 +-
 3 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c
index 864cb18..95ffa12 100644
--- a/profiles/audio/a2dp.c
+++ b/profiles/audio/a2dp.c
@@ -1887,7 +1887,7 @@ static int a2dp_source_disconnect(struct btd_service *service)
 
 	DBG("path %s", path);
 
-	return source_disconnect(service, FALSE);
+	return source_disconnect(service);
 }
 
 static int a2dp_sink_connect(struct btd_service *service)
diff --git a/profiles/audio/source.c b/profiles/audio/source.c
index 24a4353..7b129b7 100644
--- a/profiles/audio/source.c
+++ b/profiles/audio/source.c
@@ -380,16 +380,13 @@ gboolean source_new_stream(struct btd_service *service, struct avdtp *session,
 	return TRUE;
 }
 
-int source_disconnect(struct btd_service *service, gboolean shutdown)
+int source_disconnect(struct btd_service *service)
 {
 	struct source *source = btd_service_get_user_data(service);
 
 	if (!source->session)
 		return -ENOTCONN;
 
-	if (shutdown)
-		avdtp_set_device_disconnect(source->session, TRUE);
-
 	/* cancel pending connect */
 	if (source->connect_id > 0) {
 		a2dp_cancel(source->connect_id);
diff --git a/profiles/audio/source.h b/profiles/audio/source.h
index c16fb4b..a014c68 100644
--- a/profiles/audio/source.h
+++ b/profiles/audio/source.h
@@ -48,4 +48,4 @@ gboolean source_new_stream(struct btd_service *service, struct avdtp *session,
 				struct avdtp_stream *stream);
 gboolean source_setup_stream(struct btd_service *service,
 							struct avdtp *session);
-int source_disconnect(struct btd_service *service, gboolean shutdown);
+int source_disconnect(struct btd_service *service);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ 2/5] audio/AVDTP: Remove public function that are only used locally
From: Luiz Augusto von Dentz @ 2013-11-18 11:50 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384775415-10159-1-git-send-email-luiz.dentz@gmail.com>

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

---
 profiles/audio/avdtp.c | 30 ++++++++++++------------------
 profiles/audio/avdtp.h |  5 -----
 2 files changed, 12 insertions(+), 23 deletions(-)

diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
index 25b7525..de31e12 100644
--- a/profiles/audio/avdtp.c
+++ b/profiles/audio/avdtp.c
@@ -3183,8 +3183,8 @@ struct avdtp_service_capability *avdtp_stream_get_codec(
 	return NULL;
 }
 
-gboolean avdtp_stream_has_capability(struct avdtp_stream *stream,
-				struct avdtp_service_capability *cap)
+static gboolean avdtp_stream_has_capability(struct avdtp_stream *stream,
+					struct avdtp_service_capability *cap)
 {
 	GSList *l;
 	struct avdtp_service_capability *stream_cap;
@@ -3219,7 +3219,16 @@ gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
 struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
 						struct avdtp_stream *stream)
 {
-	return avdtp_get_remote_sep(stream->session, stream->rseid);
+	GSList *l;
+
+	for (l = stream->session->seps; l; l = l->next) {
+		struct avdtp_remote_sep *sep = l->data;
+
+		if (sep->seid == stream->rseid)
+			return sep;
+	}
+
+	return NULL;
 }
 
 gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
@@ -3268,21 +3277,6 @@ static int process_queue(struct avdtp *session)
 	return send_req(session, FALSE, req);
 }
 
-struct avdtp_remote_sep *avdtp_get_remote_sep(struct avdtp *session,
-						uint8_t seid)
-{
-	GSList *l;
-
-	for (l = session->seps; l; l = l->next) {
-		struct avdtp_remote_sep *sep = l->data;
-
-		if (sep->seid == seid)
-			return sep;
-	}
-
-	return NULL;
-}
-
 struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep)
 {
 	return sep->codec;
diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h
index 30ade86..3c30d78 100644
--- a/profiles/audio/avdtp.h
+++ b/profiles/audio/avdtp.h
@@ -221,9 +221,6 @@ struct avdtp *avdtp_ref(struct avdtp *session);
 struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,
 							void *data, int size);
 
-struct avdtp_remote_sep *avdtp_get_remote_sep(struct avdtp *session,
-						uint8_t seid);
-
 struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep);
 
 int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
@@ -243,8 +240,6 @@ gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
 					GSList **caps);
 struct avdtp_service_capability *avdtp_stream_get_codec(
 						struct avdtp_stream *stream);
-gboolean avdtp_stream_has_capability(struct avdtp_stream *stream,
-				struct avdtp_service_capability *cap);
 gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
 					GSList *caps);
 struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ 1/5] audio/AVDTP: Remove unused code
From: Luiz Augusto von Dentz @ 2013-11-18 11:50 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 profiles/audio/avdtp.c | 20 --------------------
 profiles/audio/avdtp.h |  8 --------
 2 files changed, 28 deletions(-)

diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c
index 9378350..25b7525 100644
--- a/profiles/audio/avdtp.c
+++ b/profiles/audio/avdtp.c
@@ -3283,31 +3283,11 @@ struct avdtp_remote_sep *avdtp_get_remote_sep(struct avdtp *session,
 	return NULL;
 }
 
-uint8_t avdtp_get_seid(struct avdtp_remote_sep *sep)
-{
-	return sep->seid;
-}
-
-uint8_t avdtp_get_type(struct avdtp_remote_sep *sep)
-{
-	return sep->type;
-}
-
 struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep)
 {
 	return sep->codec;
 }
 
-gboolean avdtp_get_delay_reporting(struct avdtp_remote_sep *sep)
-{
-	return sep->delay_reporting;
-}
-
-struct avdtp_stream *avdtp_get_stream(struct avdtp_remote_sep *sep)
-{
-	return sep->stream;
-}
-
 struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,
 							void *data, int length)
 {
diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h
index 5606506..30ade86 100644
--- a/profiles/audio/avdtp.h
+++ b/profiles/audio/avdtp.h
@@ -224,16 +224,8 @@ struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,
 struct avdtp_remote_sep *avdtp_get_remote_sep(struct avdtp *session,
 						uint8_t seid);
 
-uint8_t avdtp_get_seid(struct avdtp_remote_sep *sep);
-
-uint8_t avdtp_get_type(struct avdtp_remote_sep *sep);
-
 struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep);
 
-gboolean avdtp_get_delay_reporting(struct avdtp_remote_sep *sep);
-
-struct avdtp_stream *avdtp_get_stream(struct avdtp_remote_sep *sep);
-
 int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
 			void *user_data);
 
-- 
1.8.3.1


^ permalink raw reply related

* Re: [PATCH] android/a2dp: Use NULL for zero pointer
From: Johan Hedberg @ 2013-11-18 11:05 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1384771775-18659-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Mon, Nov 18, 2013, Andrei Emeltchenko wrote:
> ---
>  android/a2dp.c |   28 ++++++++++++++--------------
>  1 file changed, 14 insertions(+), 14 deletions(-)

Applied. Thanks.

Johan

^ permalink raw reply

* [PATCH] android/a2dp: Use NULL for zero pointer
From: Andrei Emeltchenko @ 2013-11-18 10:49 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

---
 android/a2dp.c |   28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 936c28e..4725e9e 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -280,31 +280,31 @@ static sdp_record_t *a2dp_record(void)
 		return NULL;
 
 	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(0, &root_uuid);
+	root = sdp_list_append(NULL, &root_uuid);
 	sdp_set_browse_groups(record, root);
 
 	sdp_uuid16_create(&a2dp_uuid, AUDIO_SOURCE_SVCLASS_ID);
-	svclass_id = sdp_list_append(0, &a2dp_uuid);
+	svclass_id = sdp_list_append(NULL, &a2dp_uuid);
 	sdp_set_service_classes(record, svclass_id);
 
 	sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
 	profile[0].version = a2dp_ver;
-	pfseq = sdp_list_append(0, &profile[0]);
+	pfseq = sdp_list_append(NULL, &profile[0]);
 	sdp_set_profile_descs(record, pfseq);
 
 	sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-	proto[0] = sdp_list_append(0, &l2cap_uuid);
+	proto[0] = sdp_list_append(NULL, &l2cap_uuid);
 	psm = sdp_data_alloc(SDP_UINT16, &lp);
 	proto[0] = sdp_list_append(proto[0], psm);
-	apseq = sdp_list_append(0, proto[0]);
+	apseq = sdp_list_append(NULL, proto[0]);
 
 	sdp_uuid16_create(&avdtp_uuid, AVDTP_UUID);
-	proto[1] = sdp_list_append(0, &avdtp_uuid);
+	proto[1] = sdp_list_append(NULL, &avdtp_uuid);
 	version = sdp_data_alloc(SDP_UINT16, &avdtp_ver);
 	proto[1] = sdp_list_append(proto[1], version);
 	apseq = sdp_list_append(apseq, proto[1]);
 
-	aproto = sdp_list_append(0, apseq);
+	aproto = sdp_list_append(NULL, apseq);
 	sdp_set_access_protos(record, aproto);
 
 	features = sdp_data_alloc(SDP_UINT16, &feat);
@@ -314,13 +314,13 @@ static sdp_record_t *a2dp_record(void)
 
 	free(psm);
 	free(version);
-	sdp_list_free(proto[0], 0);
-	sdp_list_free(proto[1], 0);
-	sdp_list_free(apseq, 0);
-	sdp_list_free(pfseq, 0);
-	sdp_list_free(aproto, 0);
-	sdp_list_free(root, 0);
-	sdp_list_free(svclass_id, 0);
+	sdp_list_free(proto[0], NULL);
+	sdp_list_free(proto[1], NULL);
+	sdp_list_free(apseq, NULL);
+	sdp_list_free(pfseq, NULL);
+	sdp_list_free(aproto, NULL);
+	sdp_list_free(root, NULL);
+	sdp_list_free(svclass_id, NULL);
 
 	return record;
 }
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH] android: Improve IPC helper to not send invalid status response
From: Szymon Janc @ 2013-11-18 10:44 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This fix issue with sending invalid success response from several
places where ipc_send_rsp was used for reporting success. Instead of
using using ipc_send for success response, make helper handle that.
---
 android/a2dp.c      |  2 +-
 android/bluetooth.c |  2 +-
 android/hidhost.c   |  2 +-
 android/ipc.c       |  7 ++++++-
 android/ipc.h       |  2 +-
 android/main.c      | 12 ++++++++----
 android/pan.c       |  2 +-
 android/socket.c    |  2 +-
 8 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/android/a2dp.c b/android/a2dp.c
index 936c28e..bb55e41 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -226,7 +226,7 @@ void bt_a2dp_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 		break;
 	}
 
-	ipc_send_rsp(sk, HAL_SERVICE_ID_A2DP, status);
+	ipc_send_rsp(sk, HAL_SERVICE_ID_A2DP, opcode, status);
 }
 
 static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 5c5c61e..7dc2ec3 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -2268,7 +2268,7 @@ void bt_bluetooth_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 error:
 	error("Error handling command 0x%02x status %u", opcode, status);
 
-	ipc_send_rsp(sk, HAL_SERVICE_ID_BLUETOOTH, status);
+	ipc_send_rsp(sk, HAL_SERVICE_ID_BLUETOOTH, opcode, status);
 }
 
 bool bt_bluetooth_register(int sk)
diff --git a/android/hidhost.c b/android/hidhost.c
index f5a607c..842b8ad 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -1109,7 +1109,7 @@ void bt_hid_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 		break;
 	}
 
-	ipc_send_rsp(sk, HAL_SERVICE_ID_HIDHOST, status);
+	ipc_send_rsp(sk, HAL_SERVICE_ID_HIDHOST, opcode, status);
 }
 
 static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
diff --git a/android/ipc.c b/android/ipc.c
index 729f157..34441d0 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -80,10 +80,15 @@ void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
 	}
 }
 
-void ipc_send_rsp(int sk, uint8_t service_id, uint8_t status)
+void ipc_send_rsp(int sk, uint8_t service_id, uint8_t opcode, uint8_t status)
 {
 	struct hal_status s;
 
+	if (status == HAL_STATUS_SUCCESS) {
+		ipc_send(sk, HAL_SERVICE_ID_BLUETOOTH, opcode, 0, NULL, -1);
+		return;
+	}
+
 	s.code = status;
 
 	ipc_send(sk, service_id, HAL_OP_STATUS, sizeof(s), &s, -1);
diff --git a/android/ipc.h b/android/ipc.h
index cf0f3d6..ad4a2d2 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -23,4 +23,4 @@
 
 void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
 							void *param, int fd);
-void ipc_send_rsp(int sk, uint8_t service_id, uint8_t status);
+void ipc_send_rsp(int sk, uint8_t service_id, uint8_t opcode, uint8_t status);
diff --git a/android/main.c b/android/main.c
index a4f5e84..c9733f3 100644
--- a/android/main.c
+++ b/android/main.c
@@ -122,7 +122,8 @@ static void service_register(void *buf, uint16_t len)
 	return;
 failed:
 	ipc_send_rsp(g_io_channel_unix_get_fd(hal_cmd_io),
-				HAL_SERVICE_ID_CORE, HAL_STATUS_FAILED);
+				HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+				HAL_STATUS_FAILED);
 }
 
 static void service_unregister(void *buf, uint16_t len)
@@ -164,7 +165,8 @@ static void service_unregister(void *buf, uint16_t len)
 	return;
 failed:
 	ipc_send_rsp(g_io_channel_unix_get_fd(hal_cmd_io),
-				HAL_SERVICE_ID_CORE, HAL_STATUS_FAILED);
+				HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
+				HAL_STATUS_FAILED);
 }
 
 static void handle_service_core(uint8_t opcode, void *buf, uint16_t len)
@@ -178,7 +180,8 @@ static void handle_service_core(uint8_t opcode, void *buf, uint16_t len)
 		break;
 	default:
 		ipc_send_rsp(g_io_channel_unix_get_fd(hal_cmd_io),
-				HAL_SERVICE_ID_CORE, HAL_STATUS_FAILED);
+						HAL_SERVICE_ID_CORE, opcode,
+						HAL_STATUS_FAILED);
 		break;
 	}
 }
@@ -274,7 +277,8 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
 		bt_pan_handle_cmd(fd, msg->opcode, msg->payload, msg->len);
 		break;
 	default:
-		ipc_send_rsp(fd, msg->service_id, HAL_STATUS_FAILED);
+		ipc_send_rsp(fd, msg->service_id, msg->opcode,
+							HAL_STATUS_FAILED);
 		break;
 	}
 
diff --git a/android/pan.c b/android/pan.c
index 46b3700..2a11f46 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -87,7 +87,7 @@ void bt_pan_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 		break;
 	}
 
-	ipc_send_rsp(sk, HAL_SERVICE_ID_PAN, status);
+	ipc_send_rsp(sk, HAL_SERVICE_ID_PAN, opcode, status);
 }
 
 bool bt_pan_register(int sk, const bdaddr_t *addr)
diff --git a/android/socket.c b/android/socket.c
index e580036..04bb7d1 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -75,7 +75,7 @@ void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 		break;
 	}
 
-	ipc_send_rsp(sk, HAL_SERVICE_ID_SOCK, HAL_STATUS_FAILED);
+	ipc_send_rsp(sk, HAL_SERVICE_ID_SOCK, opcode, HAL_STATUS_FAILED);
 }
 
 bool bt_socket_register(int sk, const bdaddr_t *addr)
-- 
1.8.4.2


^ permalink raw reply related

* Re: [PATCHv3 04/16] android/socket: Define structs and implement listen
From: Andrei Emeltchenko @ 2013-11-18 10:02 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20131118085535.GC30170@x220.p-661hnu-f1>

Hi Johan,

On Mon, Nov 18, 2013 at 10:55:35AM +0200, Johan Hedberg wrote:
> Hi Andrei,
> 
> On Mon, Nov 18, 2013, Andrei Emeltchenko wrote:
> > This defines structures for socket HAL. We need to emulate Android
> > sockets by sending connect/accept signals over file descriptor.
> > Handle HAL socket listen call. Create RFCOMM socket and wait for events.
> > ---
> >  android/socket.c |  118 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 116 insertions(+), 2 deletions(-)
> > 
> > diff --git a/android/socket.c b/android/socket.c
> > index e580036..276c78c 100644
> > --- a/android/socket.c
> > +++ b/android/socket.c
> > @@ -27,8 +27,12 @@
> >  
> >  #include <glib.h>
> >  #include <stdbool.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> >  
> >  #include "lib/bluetooth.h"
> > +#include "btio/btio.h"
> > +#include "lib/sdp.h"
> >  #include "log.h"
> >  #include "hal-msg.h"
> >  #include "hal-ipc.h"
> > @@ -37,13 +41,123 @@
> >  
> >  static bdaddr_t adapter_addr;
> >  
> > -static int handle_listen(void *buf)
> > +/* Simple list of RFCOMM server sockets */
> > +GList *rfcomm_srv_list = NULL;
> > +
> > +/* Simple list of RFCOMM connected sockets */
> > +GList *rfcomm_connected_list = NULL;
> 
> Didn't I suggest "servers" and "connections" as names for these?
> 
> > +struct rfcomm_slot {
> 
> The term "slot" seems a bit confusing to me. You're using this struct as
> context for both server sockets and connected sockets. Would the name
> struct rfcomm_socket make more sense? Feel free to suggest something
> else too.

rfcomm_socket is ok, what is a good name instead of rfslot? rfsock?

Best regards 
Andrei Emeltchenko 


^ permalink raw reply

* Re: [PATCHv3 16/16] android/socket: Add SDP record for OPP profile
From: Andrei Emeltchenko @ 2013-11-18  9:28 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384763179-2218-17-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi,

On Mon, Nov 18, 2013 at 10:26:19AM +0200, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> This adds SDP record for OPP shown below:
> 
> Service Name: OBEX Object Push
> Service RecHandle: 0x10002
> Service Class ID List:
>   "OBEX Object Push" (0x1105)
> Protocol Descriptor List:
>   "RFCOMM" (0x0003)
>     Channel: 9
>   "OBEX" (0x0008)
> Profile Descriptor List:
>   "OBEX Object Push" (0x1105)
>     Version: 0x0100
> ---
>  android/socket.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 94 insertions(+)
> 
> diff --git a/android/socket.c b/android/socket.c
> index 6b50014..989b876 100644
> --- a/android/socket.c
> +++ b/android/socket.c
> @@ -36,6 +36,7 @@
>  #include "lib/sdp_lib.h"
>  #include "src/sdp-client.h"
>  
> +#include "bluetooth.h"
>  #include "log.h"
>  #include "hal-msg.h"
>  #include "hal-ipc.h"
> @@ -43,6 +44,9 @@
>  #include "utils.h"
>  #include "socket.h"
>  
> +/* Use Object Transfer for all services */
> +#define SVC_HINT_OBEX 0x10
> +
>  static bdaddr_t adapter_addr;
>  
>  /* Simple list of RFCOMM server sockets */
> @@ -56,6 +60,7 @@ struct rfcomm_slot {
>  	int real_sock;	/* real RFCOMM socket */
>  	int channel;	/* RFCOMM channel */
>  	bdaddr_t dst;
> +	uint32_t service_handle;
>  };
>  
>  static struct rfcomm_slot *create_rfslot(int sock, int *hal_fd)
> @@ -86,6 +91,9 @@ static void cleanup_rfslot(struct rfcomm_slot *rfslot)
>  	if (rfslot->real_sock > 0)
>  		close(rfslot->real_sock);
>  
> +	if (rfslot->service_handle)
> +		bt_adapter_remove_record(rfslot->service_handle);
> +
>  	g_free(rfslot);
>  }
>  
> @@ -108,6 +116,90 @@ static struct {
>  	{ {0} }
>  };
>  
> +static sdp_record_t *create_opp_record(uint8_t chan)
> +{
> +	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
> +	uuid_t root_uuid, opush_uuid, rfcomm_uuid, obex_uuid;
> +	sdp_profile_desc_t profile[1];
> +	sdp_list_t *aproto, *proto[2];
> +	uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
> +	void *dtds[sizeof(formats)], *values[sizeof(formats)];
> +	unsigned int i;
> +	uint8_t dtd = SDP_UINT8;
> +	sdp_data_t *sflist;
> +	sdp_data_t *channel;
> +	sdp_record_t *record;
> +
> +	record = sdp_record_alloc();
> +	if (!record)
> +		return NULL;
> +
> +	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
> +	root = sdp_list_append(0, &root_uuid);
> +	sdp_set_browse_groups(record, root);
> +
> +	sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
> +	svclass_id = sdp_list_append(0, &opush_uuid);
> +	sdp_set_service_classes(record, svclass_id);
> +
> +	sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
> +	profile[0].version = 0x0100;
> +	pfseq = sdp_list_append(0, profile);
> +	sdp_set_profile_descs(record, pfseq);
> +
> +	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
> +	proto[0] = sdp_list_append(0, &rfcomm_uuid);
> +	channel = sdp_data_alloc(SDP_UINT8, &chan);
> +	proto[0] = sdp_list_append(proto[0], channel);
> +	apseq = sdp_list_append(apseq, proto[0]);

fixed myself to:

@@ -161,7 +161,7 @@ static sdp_record_t *create_opp_record(uint8_t chan)
        proto[0] = sdp_list_append(0, &rfcomm_uuid);
        channel = sdp_data_alloc(SDP_UINT8, &chan);
        proto[0] = sdp_list_append(proto[0], channel);
-       apseq = sdp_list_append(apseq, proto[0]);
+       apseq = sdp_list_append(0, proto[0]);
 
        sdp_uuid16_create(&obex_uuid, OBEX_UUID);
        proto[1] = sdp_list_append(0, &obex_uuid);


Best regards 
Andrei Emeltchenko 


^ permalink raw reply

* Re: [PATCHv3 04/16] android/socket: Define structs and implement listen
From: Johan Hedberg @ 2013-11-18  8:55 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1384763179-2218-5-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Mon, Nov 18, 2013, Andrei Emeltchenko wrote:
> This defines structures for socket HAL. We need to emulate Android
> sockets by sending connect/accept signals over file descriptor.
> Handle HAL socket listen call. Create RFCOMM socket and wait for events.
> ---
>  android/socket.c |  118 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 116 insertions(+), 2 deletions(-)
> 
> diff --git a/android/socket.c b/android/socket.c
> index e580036..276c78c 100644
> --- a/android/socket.c
> +++ b/android/socket.c
> @@ -27,8 +27,12 @@
>  
>  #include <glib.h>
>  #include <stdbool.h>
> +#include <unistd.h>
> +#include <errno.h>
>  
>  #include "lib/bluetooth.h"
> +#include "btio/btio.h"
> +#include "lib/sdp.h"
>  #include "log.h"
>  #include "hal-msg.h"
>  #include "hal-ipc.h"
> @@ -37,13 +41,123 @@
>  
>  static bdaddr_t adapter_addr;
>  
> -static int handle_listen(void *buf)
> +/* Simple list of RFCOMM server sockets */
> +GList *rfcomm_srv_list = NULL;
> +
> +/* Simple list of RFCOMM connected sockets */
> +GList *rfcomm_connected_list = NULL;

Didn't I suggest "servers" and "connections" as names for these?

> +struct rfcomm_slot {

The term "slot" seems a bit confusing to me. You're using this struct as
context for both server sockets and connected sockets. Would the name
struct rfcomm_socket make more sense? Feel free to suggest something
else too.

> +
> +	rfslot = g_malloc0(sizeof(*rfslot));

rfslot = g_new0(struct rfcom_slot, 1);

> +static void cleanup_rfslot(struct rfcomm_slot *rfslot)
> +{
> +	DBG("Cleanup: rfslot: %p fd %d real_sock %d chan %u",
> +		rfslot, rfslot->fd, rfslot->real_sock, rfslot->channel);

Since DBG() will anyway print the function name having an explicit
"Cleanup:" in the log message seems redundant.

> +static struct {
> +	uint8_t uuid[16];
> +	uint8_t channel;
> +} uuid_to_chan[] = {
> +	{ .uuid = {
> +	0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
> +	0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
> +	},

Why doesn't this first entry have a channel? Please indent the stuff
between { and } with an extra tab.

> +#define PBAP_DEFAULT_CHANNEL	15

I'd rather have these default channel definitions in a separate place,
probably in the beginning of the C-file where you can quickly see them.
Having them inline like this doesn't really provide any value at all
compared to just hard-coding them in the places where you have
.channel = ...

> +	{ .uuid = {
> +	0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
> +	0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
> +	},
> +#define OPP_DEFAULT_CHANNEL	9
> +	.channel = OPP_DEFAULT_CHANNEL },

Is this the missing channel from the first entry? Looks misplaced to me.

> +static int get_rfcomm_default_chan(const uint8_t *uuid)
> +{
> +	int i;
> +
> +	for (i = 0; uuid_to_chan[i].channel; i++) {
> +		if (!memcmp(uuid_to_chan[i].uuid, uuid, 16))
> +			return uuid_to_chan[i].channel;
> +	}
>  
>  	return -1;

Maybe return -ENOENT?

> +static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
> +{
> +}
> +
> +static int handle_listen(void *buf)
> +{
> +	struct hal_cmd_sock_listen *cmd = buf;
> +	struct rfcomm_slot *rfslot;
> +	GIOChannel *io;
> +	GError *err = NULL;
> +	int hal_fd = -1;

Why do you need to pre-initialize hal_fd? If create_rfslot() can fail
can won't you detect that?

> +	int chan;
> +
> +	DBG("");
> +
> +	chan = get_rfcomm_default_chan(cmd->uuid);
> +	if (chan < 0)
> +		return -1;

Maybe "return chan;"?

Johan

^ permalink raw reply

* Re: [PATCHv3 02/16] android/socket: Use static local adapter address
From: Johan Hedberg @ 2013-11-18  8:46 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1384763179-2218-3-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Mon, Nov 18, 2013, Andrei Emeltchenko wrote:
> ---
>  android/socket.c |    3 +++
>  1 file changed, 3 insertions(+)

The first two patches have been applied.

Johan

^ permalink raw reply

* Re: [PATCHv3 03/16] android/socket: Add connect signal to socket
From: Johan Hedberg @ 2013-11-18  8:45 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1384763179-2218-4-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Mon, Nov 18, 2013, Andrei Emeltchenko wrote:
> Connect signal is used to pass information to framework that socket
> is accepted.
> ---
>  android/hal-msg.h |    2 ++
>  android/socket.h  |    7 +++++++
>  2 files changed, 9 insertions(+)
> 
> diff --git a/android/hal-msg.h b/android/hal-msg.h
> index 44fd5c8..9e3a81f 100644
> --- a/android/hal-msg.h
> +++ b/android/hal-msg.h
> @@ -232,6 +232,8 @@ struct hal_cmd_sock_connect {
>  	uint8_t  flags;
>  } __attribute__((packed));
>  
> +/* Bluetooth Hidhost HAL api */
> +

This part seems unrelated to this patch?

Johan

^ permalink raw reply

* [PATCHv3 16/16] android/socket: Add SDP record for OPP profile
From: Andrei Emeltchenko @ 2013-11-18  8:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384763179-2218-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

This adds SDP record for OPP shown below:

Service Name: OBEX Object Push
Service RecHandle: 0x10002
Service Class ID List:
  "OBEX Object Push" (0x1105)
Protocol Descriptor List:
  "RFCOMM" (0x0003)
    Channel: 9
  "OBEX" (0x0008)
Profile Descriptor List:
  "OBEX Object Push" (0x1105)
    Version: 0x0100
---
 android/socket.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 6b50014..989b876 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -36,6 +36,7 @@
 #include "lib/sdp_lib.h"
 #include "src/sdp-client.h"
 
+#include "bluetooth.h"
 #include "log.h"
 #include "hal-msg.h"
 #include "hal-ipc.h"
@@ -43,6 +44,9 @@
 #include "utils.h"
 #include "socket.h"
 
+/* Use Object Transfer for all services */
+#define SVC_HINT_OBEX 0x10
+
 static bdaddr_t adapter_addr;
 
 /* Simple list of RFCOMM server sockets */
@@ -56,6 +60,7 @@ struct rfcomm_slot {
 	int real_sock;	/* real RFCOMM socket */
 	int channel;	/* RFCOMM channel */
 	bdaddr_t dst;
+	uint32_t service_handle;
 };
 
 static struct rfcomm_slot *create_rfslot(int sock, int *hal_fd)
@@ -86,6 +91,9 @@ static void cleanup_rfslot(struct rfcomm_slot *rfslot)
 	if (rfslot->real_sock > 0)
 		close(rfslot->real_sock);
 
+	if (rfslot->service_handle)
+		bt_adapter_remove_record(rfslot->service_handle);
+
 	g_free(rfslot);
 }
 
@@ -108,6 +116,90 @@ static struct {
 	{ {0} }
 };
 
+static sdp_record_t *create_opp_record(uint8_t chan)
+{
+	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+	uuid_t root_uuid, opush_uuid, rfcomm_uuid, obex_uuid;
+	sdp_profile_desc_t profile[1];
+	sdp_list_t *aproto, *proto[2];
+	uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+	void *dtds[sizeof(formats)], *values[sizeof(formats)];
+	unsigned int i;
+	uint8_t dtd = SDP_UINT8;
+	sdp_data_t *sflist;
+	sdp_data_t *channel;
+	sdp_record_t *record;
+
+	record = sdp_record_alloc();
+	if (!record)
+		return NULL;
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(0, &root_uuid);
+	sdp_set_browse_groups(record, root);
+
+	sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
+	svclass_id = sdp_list_append(0, &opush_uuid);
+	sdp_set_service_classes(record, svclass_id);
+
+	sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
+	profile[0].version = 0x0100;
+	pfseq = sdp_list_append(0, profile);
+	sdp_set_profile_descs(record, pfseq);
+
+	sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+	proto[0] = sdp_list_append(0, &rfcomm_uuid);
+	channel = sdp_data_alloc(SDP_UINT8, &chan);
+	proto[0] = sdp_list_append(proto[0], channel);
+	apseq = sdp_list_append(apseq, proto[0]);
+
+	sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+	proto[1] = sdp_list_append(0, &obex_uuid);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	aproto = sdp_list_append(0, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	for (i = 0; i < sizeof(formats); i++) {
+		dtds[i] = &dtd;
+		values[i] = &formats[i];
+	}
+	sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
+	sdp_attr_add(record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
+
+	sdp_set_info_attr(record, "OBEX Object Push", 0, 0);
+
+	sdp_data_free(channel);
+	sdp_list_free(proto[0], 0);
+	sdp_list_free(proto[1], 0);
+	sdp_list_free(apseq, 0);
+	sdp_list_free(aproto, 0);
+
+	return record;
+}
+
+static uint32_t sdp_service_register(uint8_t chan)
+{
+	sdp_record_t *record;
+
+	switch (chan) {
+	case OPP_DEFAULT_CHANNEL:
+		record = create_opp_record(chan);
+		break;
+	default:
+		DBG("Not implemented");
+		return 0;
+	}
+
+	if (bt_adapter_add_record(record, SVC_HINT_OBEX) < 0) {
+		error("Failed to register on SDP record");
+		sdp_record_free(record);
+		return 0;
+	}
+
+	return record->handle;
+}
+
 static int bt_sock_send_fd(int sock_fd, const void *buf, int len, int send_fd)
 {
 	ssize_t ret;
@@ -371,6 +463,8 @@ static int handle_listen(void *buf)
 		return -1;
 	}
 
+	rfslot->service_handle = sdp_service_register(chan);
+
 	DBG("real_sock %d fd %d hal_fd %d",
 				rfslot->real_sock, rfslot->fd, hal_fd);
 
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv3 15/16] android/socket: Close file descriptor after sending
From: Andrei Emeltchenko @ 2013-11-18  8:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384763179-2218-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

---
 android/socket.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 1bcaa23..6b50014 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -560,6 +560,7 @@ void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 			break;
 
 		ipc_send(sk, HAL_SERVICE_ID_SOCK, opcode, 0, NULL, fd);
+		close(fd);
 		return;
 	case HAL_OP_SOCK_CONNECT:
 		fd = handle_connect(buf);
@@ -567,6 +568,7 @@ void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
 			break;
 
 		ipc_send(sk, HAL_SERVICE_ID_SOCK, opcode, 0, NULL, fd);
+		close(fd);
 		return;
 	default:
 		DBG("Unhandled command, opcode 0x%x", opcode);
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv3 14/16] android/socket: Send connect signal on connect
From: Andrei Emeltchenko @ 2013-11-18  8:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384763179-2218-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Android framework expects connect signal to be sent when
remote device is connected.
---
 android/socket.c |   30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 39935e8..1bcaa23 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -377,6 +377,33 @@ static int handle_listen(void *buf)
 	return hal_fd;
 }
 
+static ssize_t sock_send_connect(struct rfcomm_slot *rfslot, bdaddr_t *bdaddr)
+{
+	struct hal_sock_connect_signal cmd;
+	ssize_t len;
+
+	DBG("");
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.size = sizeof(cmd);
+	bdaddr2android(bdaddr, cmd.bdaddr);
+	cmd.channel = rfslot->channel;
+	cmd.status = 0;
+
+	len = write(rfslot->fd, &cmd, sizeof(cmd));
+	if (len < 0) {
+		error("%s", strerror(errno));
+		return len;
+	}
+
+	if (len != (ssize_t) sizeof(cmd)) {
+		error("Error sending connect signal");
+		return -1;
+	}
+
+	return len;
+}
+
 static void connect_cb(GIOChannel *io, GError *conn_err, gpointer user_data)
 {
 	struct rfcomm_slot *rfslot = user_data;
@@ -407,6 +434,9 @@ static void connect_cb(GIOChannel *io, GError *conn_err, gpointer user_data)
 		rfslot->fd, rfslot->real_sock, rfslot->channel,
 		g_io_channel_unix_get_fd(io));
 
+	if (sock_send_connect(rfslot, &dst) < 0)
+		goto fail;
+
 	/* Handle events from Android */
 	io_stack = g_io_channel_unix_new(rfslot->fd);
 	g_io_add_watch(io_stack, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv3 13/16] android/socket: Send RFCOMM channel to framework
From: Andrei Emeltchenko @ 2013-11-18  8:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384763179-2218-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Framework expects channel to be send.
---
 android/socket.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 063681e..39935e8 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -477,6 +477,11 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
 		goto fail;
 	}
 
+	if (write(rfslot->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+		error("Error sending RFCOMM channel");
+		goto fail;
+	}
+
 	rfslot->real_sock = g_io_channel_unix_get_fd(io);
 	rfslot->channel = chan;
 	rfcomm_connected_list = g_list_append(rfcomm_connected_list, rfslot);
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv3 12/16] android/socket: Implement HAL connect call
From: Andrei Emeltchenko @ 2013-11-18  8:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384763179-2218-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

HAL connect uses similar event handlers like listen call.
---
 android/socket.c |   43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/android/socket.c b/android/socket.c
index dde000d..063681e 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -377,8 +377,49 @@ static int handle_listen(void *buf)
 	return hal_fd;
 }
 
-static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+static void connect_cb(GIOChannel *io, GError *conn_err, gpointer user_data)
 {
+	struct rfcomm_slot *rfslot = user_data;
+	GIOChannel *io_stack;
+	GError *io_err = NULL;
+	bdaddr_t dst;
+	char address[18];
+	int chan = -1;
+
+	bt_io_get(io, &io_err,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_INVALID);
+	if (io_err) {
+		error("%s", io_err->message);
+		g_error_free(io_err);
+		goto fail;
+	}
+
+	if (conn_err) {
+		error("%s", conn_err->message);
+		goto fail;
+	}
+
+	ba2str(&dst, address);
+	DBG("Connected to %s rfslot %p chan %d", address, rfslot, chan);
+
+	DBG("rfslot: fd %d real_sock %d chan %u sock %d",
+		rfslot->fd, rfslot->real_sock, rfslot->channel,
+		g_io_channel_unix_get_fd(io));
+
+	/* Handle events from Android */
+	io_stack = g_io_channel_unix_new(rfslot->fd);
+	g_io_add_watch(io_stack, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+						sock_stack_event_cb, rfslot);
+	g_io_channel_unref(io_stack);
+
+	/* Handle rfcomm events */
+	g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+				sock_rfcomm_event_cb, rfslot);
+
+	return;
+fail:
+	cleanup_rfslot(rfslot);
 }
 
 static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv3 11/16] android/socket: Parse SDP response and connect
From: Andrei Emeltchenko @ 2013-11-18  8:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384763179-2218-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Parse SDP response, find RFCOMM channel and connect.
---
 android/socket.c |   63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index c22e4ed..dde000d 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -377,9 +377,72 @@ static int handle_listen(void *buf)
 	return hal_fd;
 }
 
+static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+}
+
 static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
 {
+	struct rfcomm_slot *rfslot = data;
+	GError *gerr = NULL;
+	sdp_list_t *list;
+	GIOChannel *io;
+	int chan;
+
 	DBG("");
+
+	if (err < 0) {
+		error("Unable to get SDP record: %s", strerror(-err));
+		goto fail;
+	}
+
+	if (!recs || !recs->data) {
+		error("No SDP records found");
+		goto fail;
+	}
+
+	for (list = recs; list != NULL; list = list->next) {
+		sdp_record_t *rec = list->data;
+		sdp_list_t *protos;
+
+		if (sdp_get_access_protos(rec, &protos) < 0) {
+			error("Unable to get proto list");
+			goto fail;
+		}
+
+		chan = sdp_get_proto_port(protos, RFCOMM_UUID);
+
+		sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free,
+									NULL);
+		sdp_list_free(protos, NULL);
+	}
+
+	if (chan <= 0) {
+		error("Could not get RFCOMM channel %d", chan);
+		goto fail;
+	}
+
+	DBG("Got RFCOMM channel %d", chan);
+
+	io = bt_io_connect(connect_cb, rfslot, NULL, &gerr,
+				BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+				BT_IO_OPT_DEST_BDADDR, &rfslot->dst,
+				BT_IO_OPT_CHANNEL, chan,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+				BT_IO_OPT_INVALID);
+	if (!io) {
+		error("Failed connect: %s", gerr->message);
+		g_error_free(gerr);
+		goto fail;
+	}
+
+	rfslot->real_sock = g_io_channel_unix_get_fd(io);
+	rfslot->channel = chan;
+	rfcomm_connected_list = g_list_append(rfcomm_connected_list, rfslot);
+	return;
+
+fail:
+	cleanup_rfslot(rfslot);
 }
 
 static int handle_connect(void *buf)
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv3 10/16] android/socket: Implement socket connect HAL method
From: Andrei Emeltchenko @ 2013-11-18  8:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384763179-2218-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

First step is to query remote device for RFCOMM channel.
---
 android/socket.c |   34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index a800a77..c22e4ed 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -33,6 +33,9 @@
 #include "lib/bluetooth.h"
 #include "btio/btio.h"
 #include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "src/sdp-client.h"
+
 #include "log.h"
 #include "hal-msg.h"
 #include "hal-ipc.h"
@@ -52,6 +55,7 @@ struct rfcomm_slot {
 	int fd;		/* descriptor for communication with Java framework */
 	int real_sock;	/* real RFCOMM socket */
 	int channel;	/* RFCOMM channel */
+	bdaddr_t dst;
 };
 
 static struct rfcomm_slot *create_rfslot(int sock, int *hal_fd)
@@ -373,11 +377,37 @@ static int handle_listen(void *buf)
 	return hal_fd;
 }
 
+static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
+{
+	DBG("");
+}
+
 static int handle_connect(void *buf)
 {
-	DBG("Not implemented");
+	struct hal_cmd_sock_connect *cmd = buf;
+	struct rfcomm_slot *rfslot;
+	bdaddr_t dst;
+	uuid_t uuid;
+	int hal_fd = -1;
 
-	return -1;
+	DBG("");
+
+	android2bdaddr(cmd->bdaddr, &dst);
+	rfslot = create_rfslot(-1, &hal_fd);
+	bacpy(&rfslot->dst, &dst);
+
+	memset(&uuid, 0, sizeof(uuid));
+	uuid.type = SDP_UUID128;
+	memcpy(&uuid.value.uuid128, cmd->uuid, sizeof(uint128_t));
+
+	if (bt_search_service(&adapter_addr, &dst, &uuid, sdp_search_cb, rfslot,
+								NULL) < 0) {
+		error("Failed to search SDP records");
+		cleanup_rfslot(rfslot);
+		return -1;
+	}
+
+	return hal_fd;
 }
 
 void bt_sock_handle_cmd(int sk, uint8_t opcode, void *buf, uint16_t len)
-- 
1.7.10.4


^ permalink raw reply related

* [PATCHv3 09/16] android/socket: Write channel to Android fd
From: Andrei Emeltchenko @ 2013-11-18  8:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1384763179-2218-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Android framework expects to receive channel number as int.
---
 android/socket.c |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/android/socket.c b/android/socket.c
index 4886158..a800a77 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -360,6 +360,13 @@ static int handle_listen(void *buf)
 	rfslot->real_sock = g_io_channel_unix_get_fd(io);
 	rfcomm_srv_list = g_list_append(rfcomm_srv_list, rfslot);
 
+	/* TODO: Check this */
+	if (write(rfslot->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+		error("Error sending RFCOMM channel");
+		cleanup_rfslot(rfslot);
+		return -1;
+	}
+
 	DBG("real_sock %d fd %d hal_fd %d",
 				rfslot->real_sock, rfslot->fd, hal_fd);
 
-- 
1.7.10.4


^ permalink raw reply related


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