2013-11-25 11:22:50

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFCv2 0/7] Socket HAL part2

From: Andrei Emeltchenko <[email protected]>

These are fixes and some missing functionality for Socket HAL.

Andrei Emeltchenko (7):
android/socket: Check that create_record function exist
android/socket: Use default sec_level for listen
android/socket: Add error printing possible close() failure
android/socket: Use security level for connect
android/socket: Keep server iochannel reference
android/socket: Handle Android events for server socket
android/socket: Check create_rfsock returns valid structure

android/socket.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 88 insertions(+), 16 deletions(-)

--
1.8.3.2



2013-11-25 11:22:52

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFCv2 2/7] android/socket: Use default sec_level for listen

From: Andrei Emeltchenko <[email protected]>

Set default security level low for OPP and SPP and medium for PBAP and MAS.
Default security level would be low for listening without profile.
---
android/socket.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index 63587ee..0885fa2 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -344,6 +344,7 @@ static struct profile_info {
},
.channel = PBAP_DEFAULT_CHANNEL,
.svc_hint = SVC_HINT_OBEX,
+ .sec_level = BT_IO_SEC_MEDIUM,
.create_record = create_pbap_record
}, {
.uuid = {
@@ -352,13 +353,17 @@ static struct profile_info {
},
.channel = OPP_DEFAULT_CHANNEL,
.svc_hint = SVC_HINT_OBEX,
+ .sec_level = BT_IO_SEC_LOW,
.create_record = create_opp_record
}, {
.uuid = {
0x00, 0x00, 0x11, 0x32, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
- .channel = MAS_DEFAULT_CHANNEL
+ .channel = MAS_DEFAULT_CHANNEL,
+ .svc_hint = 0,
+ .sec_level = BT_IO_SEC_MEDIUM,
+ .create_record = NULL
}, {
.uuid = {
0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
@@ -366,6 +371,7 @@ static struct profile_info {
},
.channel = SPP_DEFAULT_CHANNEL,
.svc_hint = 0,
+ .sec_level = BT_IO_SEC_LOW,
.create_record = create_spp_record
},
};
@@ -639,6 +645,7 @@ static int handle_listen(void *buf)
struct hal_cmd_sock_listen *cmd = buf;
struct profile_info *profile;
struct rfcomm_sock *rfsock;
+ BtIOSecLevel sec_level;
GIOChannel *io;
GError *err = NULL;
int hal_fd;
@@ -650,10 +657,14 @@ static int handle_listen(void *buf)
if (!profile) {
if (!cmd->channel)
return -1;
- else
+ else {
chan = cmd->channel;
- } else
+ sec_level = BT_IO_SEC_LOW;
+ }
+ } else {
chan = profile->channel;
+ sec_level = profile->sec_level;
+ }

DBG("rfcomm channel %d svc_name %s", chan, cmd->name);

@@ -664,6 +675,7 @@ static int handle_listen(void *buf)
io = bt_io_listen(accept_cb, NULL, rfsock, NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
BT_IO_OPT_CHANNEL, chan,
+ BT_IO_OPT_SEC_LEVEL, sec_level,
BT_IO_OPT_INVALID);
if (!io) {
error("Failed listen: %s", err->message);
--
1.8.3.2


2013-11-25 11:22:55

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFCv2 5/7] android/socket: Keep server iochannel reference

From: Andrei Emeltchenko <[email protected]>

server io channel reference will be stored in rfsock structure
and might be deleted when Android end closes connection or when
HAL makes cleanup() call.
---
android/socket.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index 24503c5..93ace07 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -70,6 +70,8 @@ struct rfcomm_sock {
guint rfcomm_watch;
guint stack_watch;

+ GIOChannel *srv_io;
+
bdaddr_t dst;
uint32_t service_handle;

@@ -121,6 +123,11 @@ static void cleanup_rfsock(struct rfcomm_sock *rfsock)
if (rfsock->service_handle)
bt_adapter_remove_record(rfsock->service_handle);

+ if (rfsock->srv_io) {
+ g_io_channel_shutdown(rfsock->srv_io, TRUE, NULL);
+ g_io_channel_unref(rfsock->srv_io);
+ }
+
g_free(rfsock);
}

@@ -696,9 +703,7 @@ static int handle_listen(void *buf)
rfsock->real_sock = g_io_channel_unix_get_fd(io);
servers = g_list_append(servers, rfsock);

- /* TODO: Add server watch */
- g_io_channel_set_close_on_unref(io, TRUE);
- g_io_channel_unref(io);
+ rfsock->srv_io = io;

DBG("real_sock %d fd %d hal_fd %d", rfsock->real_sock, rfsock->fd,
hal_fd);
--
1.8.3.2


2013-11-25 11:22:51

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFCv2 1/7] android/socket: Check that create_record function exist

From: Andrei Emeltchenko <[email protected]>

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

diff --git a/android/socket.c b/android/socket.c
index 22472b9..63587ee 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -688,7 +688,7 @@ static int handle_listen(void *buf)
return -1;
}

- if (profile)
+ if (profile && profile->create_record)
rfsock->service_handle = sdp_service_register(profile,
cmd->name);

--
1.8.3.2


2013-11-25 11:22:57

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFCv2 7/7] android/socket: Check create_rfsock returns valid structure

From: Andrei Emeltchenko <[email protected]>

---
android/socket.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/android/socket.c b/android/socket.c
index 45f9b91..bbc29dc 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -644,6 +644,12 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)

sock_acc = g_io_channel_unix_get_fd(io);
rfsock_acc = create_rfsock(sock_acc, &hal_fd);
+ if (!rfsock_acc) {
+ g_io_channel_shutdown(io, TRUE, NULL);
+ g_io_channel_unref(io);
+ return;
+ }
+
connections = g_list_append(connections, rfsock_acc);

DBG("rfsock: fd %d real_sock %d chan %u sock %d",
@@ -904,8 +910,11 @@ static int handle_connect(void *buf)

DBG("");

- android2bdaddr(cmd->bdaddr, &dst);
rfsock = create_rfsock(-1, &hal_fd);
+ if (!rfsock)
+ return -1;
+
+ android2bdaddr(cmd->bdaddr, &dst);
bacpy(&rfsock->dst, &dst);

memset(&uuid, 0, sizeof(uuid));
--
1.8.3.2


2013-11-25 11:22:56

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFCv2 6/7] android/socket: Handle Android events for server socket

From: Andrei Emeltchenko <[email protected]>

Add watch for tracking events from Android framework for server socket.
---
android/socket.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/android/socket.c b/android/socket.c
index 93ace07..45f9b91 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -593,6 +593,24 @@ static bool sock_send_accept(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr,
return true;
}

+static gboolean sock_server_stack_event_cb(GIOChannel *io, GIOCondition cond,
+ gpointer data)
+{
+ struct rfcomm_sock *rfsock = data;
+
+ DBG("");
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+ error("Socket error: sock %d cond %d",
+ g_io_channel_unix_get_fd(io), cond);
+ cleanup_rfsock(rfsock);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
{
struct rfcomm_sock *rfsock = user_data;
@@ -662,7 +680,8 @@ static int handle_listen(void *buf)
struct profile_info *profile;
struct rfcomm_sock *rfsock;
BtIOSecLevel sec_level;
- GIOChannel *io;
+ GIOChannel *io, *io_stack;
+ GIOCondition cond;
GError *err = NULL;
int hal_fd;
int chan;
@@ -705,6 +724,12 @@ static int handle_listen(void *buf)

rfsock->srv_io = io;

+ /* Handle events from Android */
+ cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+ io_stack = g_io_channel_unix_new(rfsock->fd);
+ g_io_add_watch(io_stack, cond, sock_server_stack_event_cb, rfsock);
+ g_io_channel_unref(io_stack);
+
DBG("real_sock %d fd %d hal_fd %d", rfsock->real_sock, rfsock->fd,
hal_fd);

--
1.8.3.2


2013-11-25 11:22:53

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFCv2 3/7] android/socket: Add error printing possible close() failure

From: Andrei Emeltchenko <[email protected]>

---
android/socket.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/android/socket.c b/android/socket.c
index 0885fa2..399590e 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -96,10 +96,15 @@ static void cleanup_rfsock(struct rfcomm_sock *rfsock)
DBG("rfsock: %p fd %d real_sock %d chan %u",
rfsock, rfsock->fd, rfsock->real_sock, rfsock->channel);

- if (rfsock->fd > 0)
- close(rfsock->fd);
- if (rfsock->real_sock > 0)
- close(rfsock->real_sock);
+ if (rfsock->fd >= 0)
+ if (close(rfsock->fd) < 0)
+ error("close() fd %d failed: %s", rfsock->fd,
+ strerror(errno));
+
+ if (rfsock->real_sock >= 0)
+ if (close(rfsock->real_sock) < 0)
+ error("close() fd %d: failed: %s", rfsock->real_sock,
+ strerror(errno));

if (rfsock->rfcomm_watch > 0)
if (!g_source_remove(rfsock->rfcomm_watch))
@@ -890,7 +895,10 @@ 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);
+
+ if (close(fd) < 0)
+ error("close() fd %d failed: %s", fd, strerror(errno));
+
return;
case HAL_OP_SOCK_CONNECT:
fd = handle_connect(buf);
@@ -898,7 +906,10 @@ 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);
+
+ if (close(fd) < 0)
+ error("close() fd %d failed: %s", fd, strerror(errno));
+
return;
default:
DBG("Unhandled command, opcode 0x%x", opcode);
--
1.8.3.2


2013-11-25 11:22:54

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFCv2 4/7] android/socket: Use security level for connect

From: Andrei Emeltchenko <[email protected]>

Use low security level for connections without profile and default
sec_level for others. rfsock now has pointer to profile info for
outcoming connections.
---
android/socket.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/android/socket.c b/android/socket.c
index 399590e..24503c5 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -60,6 +60,8 @@ GList *servers = NULL;
/* Simple list of RFCOMM connected sockets */
GList *connections = NULL;

+struct profile_info;
+
struct rfcomm_sock {
int fd; /* descriptor for communication with Java framework */
int real_sock; /* real RFCOMM socket */
@@ -70,6 +72,8 @@ struct rfcomm_sock {

bdaddr_t dst;
uint32_t service_handle;
+
+ struct profile_info *profile;
};

static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
@@ -785,6 +789,7 @@ fail:
static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
{
struct rfcomm_sock *rfsock = data;
+ BtIOSecLevel sec_level = BT_IO_SEC_LOW;
GError *gerr = NULL;
sdp_list_t *list;
GIOChannel *io;
@@ -828,11 +833,14 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)

DBG("Got RFCOMM channel %d", chan);

+ if (rfsock->profile)
+ sec_level = rfsock->profile->sec_level;
+
io = bt_io_connect(connect_cb, rfsock, NULL, &gerr,
BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
BT_IO_OPT_DEST_BDADDR, &rfsock->dst,
BT_IO_OPT_CHANNEL, chan,
- BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_SEC_LEVEL, sec_level,
BT_IO_OPT_INVALID);
if (!io) {
error("Failed connect: %s", gerr->message);
@@ -874,6 +882,8 @@ static int handle_connect(void *buf)
uuid.type = SDP_UUID128;
memcpy(&uuid.value.uuid128, cmd->uuid, sizeof(uint128_t));

+ rfsock->profile = get_profile_by_uuid(cmd->uuid);
+
if (bt_search_service(&adapter_addr, &dst, &uuid, sdp_search_cb, rfsock,
NULL) < 0) {
error("Failed to search SDP records");
--
1.8.3.2