Hi,
Current socket HAL implementation is missing major feature which is
ability to register RFCOMM server from application (so use some UUID
and assign channel number dynamically). This corresponds to
BluetoothAdapter::listenUsing(insecure)RfcommWithServiceRecord APIs
in Android.
This series of patches adds this feature with other required fixes
and also some does some minor refactoring.
Andrzej Kaczmarek (11):
android/bluetooth: Handle 128-bit UUIDs
android/socket: Refactor socket related symbol names
android/socket: Improve logging
android/socket: Simplify SDP records handling
android/socket: Make servers list as static array
android/tester: Update test data
android/socket: Add support for dynamic channel numbers
android/socket: Register SDP record for application service
android/socket: Include HF AG in built-in profiles
android/socket: Update channel numbers
android/socket: Fix sockets security
android/android-tester.c | 2 +-
android/bluetooth.c | 61 ++---
android/hal-msg.h | 3 +
android/socket.c | 658 +++++++++++++++++++++++------------------------
4 files changed, 349 insertions(+), 375 deletions(-)
--
1.8.5.3
Hi Andrei,
On Wednesday 12 of February 2014 11:57:41 Andrei Emeltchenko wrote:
> Hi Andrzej,
>
> On Tue, Feb 11, 2014 at 05:58:10PM +0100, Andrzej Kaczmarek wrote:
> > Hi,
> >
> > Current socket HAL implementation is missing major feature which is
> > ability to register RFCOMM server from application (so use some UUID
> > and assign channel number dynamically). This corresponds to
> > BluetoothAdapter::listenUsing(insecure)RfcommWithServiceRecord APIs
> > in Android.
>
> Support dynamic RFCOMM sockets looks god though I do not know why renaming
> of socket names is really needed.
I find new names a bit easier to understand and this is now applied.
--
BR
Szymon Janc
Hi Andrzej,
On Tuesday 11 of February 2014 17:58:10 Andrzej Kaczmarek wrote:
> Hi,
>
> Current socket HAL implementation is missing major feature which is
> ability to register RFCOMM server from application (so use some UUID
> and assign channel number dynamically). This corresponds to
> BluetoothAdapter::listenUsing(insecure)RfcommWithServiceRecord APIs
> in Android.
>
> This series of patches adds this feature with other required fixes
> and also some does some minor refactoring.
>
> Andrzej Kaczmarek (11):
> android/bluetooth: Handle 128-bit UUIDs
> android/socket: Refactor socket related symbol names
> android/socket: Improve logging
> android/socket: Simplify SDP records handling
> android/socket: Make servers list as static array
> android/tester: Update test data
> android/socket: Add support for dynamic channel numbers
> android/socket: Register SDP record for application service
> android/socket: Include HF AG in built-in profiles
> android/socket: Update channel numbers
> android/socket: Fix sockets security
>
> android/android-tester.c | 2 +-
> android/bluetooth.c | 61 ++---
> android/hal-msg.h | 3 +
> android/socket.c | 658
> +++++++++++++++++++++++------------------------ 4 files changed, 349
> insertions(+), 375 deletions(-)
All patches in this set are now upstream, thanks a lot.
--
BR
Szymon Janc
Hi Andrzej,
On Tue, Feb 11, 2014 at 05:58:10PM +0100, Andrzej Kaczmarek wrote:
> Hi,
>
> Current socket HAL implementation is missing major feature which is
> ability to register RFCOMM server from application (so use some UUID
> and assign channel number dynamically). This corresponds to
> BluetoothAdapter::listenUsing(insecure)RfcommWithServiceRecord APIs
> in Android.
Support dynamic RFCOMM sockets looks god though I do not know why renaming
of socket names is really needed.
Best regards
Andrei Emeltchenko
>
> This series of patches adds this feature with other required fixes
> and also some does some minor refactoring.
>
> Andrzej Kaczmarek (11):
> android/bluetooth: Handle 128-bit UUIDs
> android/socket: Refactor socket related symbol names
> android/socket: Improve logging
> android/socket: Simplify SDP records handling
> android/socket: Make servers list as static array
> android/tester: Update test data
> android/socket: Add support for dynamic channel numbers
> android/socket: Register SDP record for application service
> android/socket: Include HF AG in built-in profiles
> android/socket: Update channel numbers
> android/socket: Fix sockets security
>
> android/android-tester.c | 2 +-
> android/bluetooth.c | 61 ++---
> android/hal-msg.h | 3 +
> android/socket.c | 658 +++++++++++++++++++++++------------------------
> 4 files changed, 349 insertions(+), 375 deletions(-)
>
> --
> 1.8.5.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Since there is only small, fixed number of channels to allocate for
RFCOMM servers we can store them in static array. This will make
lookup for free channel simpler once we add support to assign channel
numbers dynamically.
At startup, channels reserved for built-in services which have static
channel number are marked as reserved so they cannot be assigned for
other service.
---
android/socket.c | 44 +++++++++++++++++++++++++++++++++++++-------
1 file changed, 37 insertions(+), 7 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 32de91a..4e823dd 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -45,6 +45,8 @@
#include "utils.h"
#include "socket.h"
+#define RFCOMM_CHANNEL_MAX 30
+
#define SPP_DEFAULT_CHANNEL 3
#define OPP_DEFAULT_CHANNEL 9
#define PBAP_DEFAULT_CHANNEL 15
@@ -64,9 +66,6 @@ static bdaddr_t adapter_addr;
static const uint8_t zero_uuid[16] = { 0 };
-/* Simple list of RFCOMM server sockets */
-GList *servers = NULL;
-
/* Simple list of RFCOMM connected sockets */
GList *connections = NULL;
@@ -90,6 +89,13 @@ struct rfcomm_sock {
const struct profile_info *profile;
};
+struct rfcomm_channel {
+ bool reserved;
+ struct rfcomm_sock *rfsock;
+};
+
+static struct rfcomm_channel servers[RFCOMM_CHANNEL_MAX + 1];
+
static int rfsock_set_buffer(struct rfcomm_sock *rfsock)
{
socklen_t len = sizeof(int);
@@ -599,7 +605,7 @@ static gboolean jv_sock_server_event_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
if (cond & (G_IO_ERR | G_IO_HUP )) {
- servers = g_list_remove(servers, rfsock);
+ servers[rfsock->channel].rfsock = NULL;
cleanup_rfsock(rfsock);
}
@@ -690,7 +696,8 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
DBG("chan %d flags 0x%02x uuid %s name %s", chan, flags, uuid_str,
name);
- if (!memcmp(uuid, zero_uuid, sizeof(zero_uuid)) && chan <= 0) {
+ if ((!memcmp(uuid, zero_uuid, sizeof(zero_uuid)) && chan <= 0) ||
+ (chan > RFCOMM_CHANNEL_MAX)) {
error("Invalid rfcomm listen params");
return HAL_STATUS_INVALID;
}
@@ -706,12 +713,19 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
sec_level = profile->sec_level;
}
+ if (servers[chan].rfsock != NULL) {
+ error("Channel already registered (%d)", chan);
+ return HAL_STATUS_BUSY;
+ }
+
DBG("chan %d sec_level %d", chan, sec_level);
rfsock = create_rfsock(-1, hal_sock);
if (!rfsock)
return HAL_STATUS_FAILED;
+ rfsock->channel = chan;
+
io = bt_io_listen(accept_cb, NULL, rfsock, NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
BT_IO_OPT_CHANNEL, chan,
@@ -750,7 +764,7 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
rfsock->service_handle = sdp_service_register(profile, name);
- servers = g_list_append(servers, rfsock);
+ servers[chan].rfsock = rfsock;
return HAL_STATUS_SUCCESS;
@@ -1050,8 +1064,17 @@ static const struct ipc_handler cmd_handlers[] = {
void bt_socket_register(const bdaddr_t *addr)
{
+ size_t i;
+
DBG("");
+ /* make sure channels assigned for profiles are reserved and not used
+ * for app services
+ */
+ for (i = 0; i < G_N_ELEMENTS(profiles); i++)
+ if (profiles[i].channel)
+ servers[profiles[i].channel].reserved = true;
+
bacpy(&adapter_addr, addr);
ipc_register(HAL_SERVICE_ID_SOCK, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
@@ -1059,10 +1082,17 @@ void bt_socket_register(const bdaddr_t *addr)
void bt_socket_unregister(void)
{
+ int ch;
+
DBG("");
g_list_free_full(connections, cleanup_rfsock);
- g_list_free_full(servers, cleanup_rfsock);
+
+ for (ch = 0; ch <= RFCOMM_CHANNEL_MAX; ch++)
+ if (servers[ch].rfsock)
+ cleanup_rfsock(&servers[ch]);
+
+ memset(servers, 0, sizeof(servers));
ipc_unregister(HAL_SERVICE_ID_SOCK);
}
--
1.8.5.3
This patch adds entry for HF AG profile in built-in profiles list. This
it to reserve channel number so it's not assigned to other service
registered by application. Method for creating SDP record is not
provided so it's not possible for application to register HF AG service
by mistake (this can be only done by handsfree profile implementation).
---
android/socket.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index 9175bf3..4dcb5fc 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -49,6 +49,7 @@
#define SPP_DEFAULT_CHANNEL 3
#define OPP_DEFAULT_CHANNEL 9
+#define HFAG_DEFAULT_CHANNEL 13
#define PBAP_DEFAULT_CHANNEL 15
#define MAS_DEFAULT_CHANNEL 16
@@ -375,6 +376,15 @@ static const struct profile_info {
} profiles[] = {
{
.uuid = {
+ 0x00, 0x00, 0x11, 0x1F, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
+ },
+ .channel = HFAG_DEFAULT_CHANNEL,
+ .svc_hint = 0,
+ .sec_level = BT_IO_SEC_MEDIUM,
+ .create_record = NULL
+ }, {
+ .uuid = {
0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
@@ -742,6 +752,9 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
if (!profile) {
sec_level = BT_IO_SEC_MEDIUM;
} else {
+ if (!profile->create_record)
+ return HAL_STATUS_INVALID;
+
chan = profile->channel;
sec_level = profile->sec_level;
}
--
1.8.5.3
This patch makes logging more consistent by including rfsock pointer in
most messages which identifies socket structure unambigously (instead
of using bunch of file descriptors for the same purpose) and puts other
parameters in order in some cases.
Additionally, some new logs are introduced to better track socket
structures and connections lifetime.
---
android/socket.c | 71 ++++++++++++++++++++++++++++++++++----------------------
1 file changed, 43 insertions(+), 28 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 107042e..5045911 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -121,8 +121,8 @@ static void cleanup_rfsock(gpointer data)
{
struct rfcomm_sock *rfsock = data;
- DBG("rfsock: %p jv_sock %d bt_sock %d chan %u",
- rfsock, rfsock->jv_sock, rfsock->bt_sock, rfsock->channel);
+ DBG("rfsock %p bt_sock %d jv_sock %d", rfsock, rfsock->bt_sock,
+ rfsock->jv_sock);
if (rfsock->jv_sock >= 0)
if (close(rfsock->jv_sock) < 0)
@@ -167,6 +167,8 @@ static struct rfcomm_sock *create_rfsock(int bt_sock, int *hal_sock)
*hal_sock = fds[1];
rfsock->bt_sock = bt_sock;
+ DBG("rfsock %p", rfsock);
+
if (bt_sock < 0)
return rfsock;
@@ -619,8 +621,7 @@ static gboolean jv_sock_client_event_cb(GIOChannel *io, GIOCondition cond,
}
if (cond & (G_IO_ERR | G_IO_NVAL)) {
- error("Socket error: sock %d cond %d",
- g_io_channel_unix_get_fd(io), cond);
+ error("Socket %d error", g_io_channel_unix_get_fd(io));
goto fail;
}
@@ -639,6 +640,8 @@ static gboolean jv_sock_client_event_cb(GIOChannel *io, GIOCondition cond,
return TRUE;
fail:
+ DBG("rfsock %p jv_sock %d cond %d", rfsock, rfsock->jv_sock, cond);
+
connections = g_list_remove(connections, rfsock);
cleanup_rfsock(rfsock);
@@ -657,8 +660,7 @@ static gboolean bt_sock_event_cb(GIOChannel *io, GIOCondition cond,
}
if (cond & (G_IO_ERR | G_IO_NVAL)) {
- error("Socket error: sock %d cond %d",
- g_io_channel_unix_get_fd(io), cond);
+ error("Socket %d error", g_io_channel_unix_get_fd(io));
goto fail;
}
@@ -677,6 +679,8 @@ static gboolean bt_sock_event_cb(GIOChannel *io, GIOCondition cond,
return TRUE;
fail:
+ DBG("rfsock %p bt_sock %d cond %d", rfsock, rfsock->bt_sock, cond);
+
connections = g_list_remove(connections, rfsock);
cleanup_rfsock(rfsock);
@@ -710,7 +714,7 @@ static gboolean jv_sock_server_event_cb(GIOChannel *io, GIOCondition cond,
{
struct rfcomm_sock *rfsock = data;
- DBG("sock %d cond %d", g_io_channel_unix_get_fd(io), cond);
+ DBG("rfsock %p jv_sock %d cond %d", rfsock, rfsock->jv_sock, cond);
if (cond & G_IO_NVAL)
return FALSE;
@@ -752,7 +756,8 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
}
ba2str(&dst, address);
- DBG("Incoming connection from %s rfsock %p", address, rfsock);
+ DBG("Incoming connection from %s on channel %d (rfsock %p)", address,
+ rfsock->channel, rfsock);
new_sock = g_io_channel_unix_get_fd(io);
new_rfsock = create_rfsock(new_sock, &hal_sock);
@@ -761,9 +766,8 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
return;
}
- DBG("rfsock: jv_sock %d bt_sock %d chan %u new_sock %d",
- rfsock->jv_sock, rfsock->bt_sock, rfsock->channel,
- new_sock);
+ DBG("new rfsock %p bt_sock %d jv_sock %d hal_sock %d", new_rfsock,
+ new_rfsock->bt_sock, new_rfsock->jv_sock, hal_sock);
if (!sock_send_accept(rfsock, &dst, hal_sock)) {
cleanup_rfsock(new_rfsock);
@@ -786,10 +790,6 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
g_io_channel_set_close_on_unref(io, FALSE);
new_rfsock->bt_watch = id;
-
- DBG("rfsock %p rfsock_acc %p jv_watch %d bt_watch %d",
- rfsock, new_rfsock, new_rfsock->jv_watch,
- new_rfsock->bt_watch);
}
static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
@@ -802,8 +802,14 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
GIOCondition cond;
GError *err = NULL;
guint id;
+ uuid_t uu;
+ char uuid_str[32];
- DBG("");
+ sdp_uuid128_create(&uu, uuid);
+ sdp_uuid2strn(&uu, uuid_str, sizeof(uuid_str));
+
+ DBG("chan %d flags 0x%02x uuid %s name %s", chan, flags, uuid_str,
+ name);
if (!memcmp(uuid, zero_uuid, sizeof(zero_uuid)) && chan <= 0) {
error("Invalid rfcomm listen params");
@@ -821,7 +827,7 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
sec_level = profile->sec_level;
}
- DBG("rfcomm channel %d svc_name %s", chan, name);
+ DBG("chan %d sec_level %d", chan, sec_level);
rfsock = create_rfsock(-1, hal_sock);
if (!rfsock)
@@ -853,8 +859,10 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
rfsock->jv_watch = id;
- DBG("bt_sock %d jv_sock %d hal_sock %d", rfsock->bt_sock,
- rfsock->jv_sock, *hal_sock);
+ DBG("rfsock %p bt_sock %d jv_sock %d hal_sock %d", rfsock,
+ rfsock->bt_sock,
+ rfsock->jv_sock,
+ *hal_sock);
if (write(rfsock->jv_sock, &chan, sizeof(chan)) != sizeof(chan)) {
error("Error sending RFCOMM channel");
@@ -948,11 +956,8 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
}
ba2str(dst, address);
- DBG("Connected to %s", address);
-
- DBG("rfsock: jv_sock %d bt_sock %d chan %u sock %d",
- rfsock->jv_sock, rfsock->bt_sock, rfsock->channel,
- g_io_channel_unix_get_fd(io));
+ DBG("Connected to %s on channel %d (rfsock %p)", address,
+ rfsock->channel, rfsock);
if (!sock_send_connect(rfsock, dst))
goto fail;
@@ -987,6 +992,8 @@ static bool do_rfcomm_connect(struct rfcomm_sock *rfsock, int chan)
if (rfsock->profile)
sec_level = rfsock->profile->sec_level;
+ DBG("rfsock %p sec_level %d chan %d", rfsock, sec_level, chan);
+
io = bt_io_connect(connect_cb, rfsock, NULL, &gerr,
BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
BT_IO_OPT_DEST_BDADDR, &rfsock->dst,
@@ -1070,7 +1077,16 @@ static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
int *hal_sock)
{
struct rfcomm_sock *rfsock;
+ char address[18];
uuid_t uu;
+ char uuid_str[32];
+
+ sdp_uuid128_create(&uu, uuid);
+ sdp_uuid2strn(&uu, uuid_str, sizeof(uuid_str));
+ ba2str(addr, address);
+
+ DBG("addr %s chan %d flags 0x%02x uuid %s", address, chan, flags,
+ uuid_str);
if ((!memcmp(uuid, zero_uuid, sizeof(zero_uuid)) && chan <= 0) ||
!bacmp(addr, BDADDR_ANY)) {
@@ -1082,16 +1098,15 @@ static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
if (!rfsock)
return HAL_STATUS_FAILED;
+ DBG("rfsock %p jv_sock %d hal_sock %d", rfsock, rfsock->jv_sock,
+ *hal_sock);
+
bacpy(&rfsock->dst, addr);
if (!memcmp(uuid, zero_uuid, sizeof(zero_uuid))) {
if (!do_rfcomm_connect(rfsock, chan))
goto failed;
} else {
- memset(&uu, 0, sizeof(uu));
- uu.type = SDP_UUID128;
- memcpy(&uu.value.uuid128, uuid, sizeof(uint128_t));
-
rfsock->profile = get_profile_by_uuid(uuid);
if (bt_search_service(&adapter_addr, &rfsock->dst, &uu,
--
1.8.5.3
Socket security shall be based on flags passed from HAL.
Android public API uses both encrypt and auth flags for "secure"
sockets which should be mapped to high security on our side, but since
this would also trigger requirement for 16-digits pin code (which is
not used in Android) we'll ignore auth flag and use either low or
medium security based on encrypt flag value only.
---
android/hal-msg.h | 3 +++
android/socket.c | 29 +++++++++++++++++++----------
2 files changed, 22 insertions(+), 10 deletions(-)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index aba98ed..6ef00f9 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -235,6 +235,9 @@ struct hal_cmd_le_test_mode {
#define HAL_SOCK_SCO 0x02
#define HAL_SOCK_L2CAP 0x03
+#define HAL_SOCK_FLAG_ENCRYPT 0x01
+#define HAL_SOCK_FLAG_AUTH 0x02
+
#define HAL_OP_SOCK_LISTEN 0x01
struct hal_cmd_sock_listen {
uint8_t type;
diff --git a/android/socket.c b/android/socket.c
index c790c24..4e9121d 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -70,6 +70,7 @@ GList *connections = NULL;
struct rfcomm_sock {
int channel; /* RFCOMM channel */
+ BtIOSecLevel sec_level;
/* for socket to BT */
int bt_sock;
@@ -84,8 +85,6 @@ struct rfcomm_sock {
uint8_t *buf;
int buf_size;
-
- const struct profile_info *profile;
};
struct rfcomm_channel {
@@ -721,6 +720,19 @@ static int find_free_channel(void)
return 0;
}
+static BtIOSecLevel get_sec_level(uint8_t flags)
+{
+ /* HAL_SOCK_FLAG_AUTH should require MITM but in our case setting
+ * security to BT_IO_SEC_HIGH would also require 16-digits PIN code
+ * for pre-2.1 devices which is not what Android expects. For this
+ * reason we ignore this flag to not break apps which use "secure"
+ * sockets (have both auth and encrypt flags set, there is no public
+ * API in Android which should provide proper high security socket).
+ */
+ return flags & HAL_SOCK_FLAG_ENCRYPT ? BT_IO_SEC_MEDIUM :
+ BT_IO_SEC_LOW;
+}
+
static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
uint8_t flags, int *hal_sock)
{
@@ -748,7 +760,7 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
profile = get_profile_by_uuid(uuid);
if (!profile) {
- sec_level = BT_IO_SEC_MEDIUM;
+ sec_level = get_sec_level(flags);
} else {
if (!profile->create_record)
return HAL_STATUS_INVALID;
@@ -931,20 +943,16 @@ fail:
static bool do_rfcomm_connect(struct rfcomm_sock *rfsock, int chan)
{
- BtIOSecLevel sec_level = BT_IO_SEC_MEDIUM;
GIOChannel *io;
GError *gerr = NULL;
- if (rfsock->profile)
- sec_level = rfsock->profile->sec_level;
-
- DBG("rfsock %p sec_level %d chan %d", rfsock, sec_level, chan);
+ DBG("rfsock %p sec_level %d chan %d", rfsock, rfsock->sec_level, chan);
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, sec_level,
+ BT_IO_OPT_SEC_LEVEL, rfsock->sec_level,
BT_IO_OPT_INVALID);
if (!io) {
error("Failed connect: %s", gerr->message);
@@ -1047,13 +1055,14 @@ static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
DBG("rfsock %p jv_sock %d hal_sock %d", rfsock, rfsock->jv_sock,
*hal_sock);
+ rfsock->sec_level = get_sec_level(flags);
+
bacpy(&rfsock->dst, addr);
if (!memcmp(uuid, zero_uuid, sizeof(zero_uuid))) {
if (!do_rfcomm_connect(rfsock, chan))
goto failed;
} else {
- rfsock->profile = get_profile_by_uuid(uuid);
if (bt_search_service(&adapter_addr, &rfsock->dst, &uu,
sdp_search_cb, rfsock, NULL, 0) < 0) {
--
1.8.5.3
OPP and PBAP channel numbers are set to same values as in Bluedroid.
Both MAP and SPP use channel numbers assigned dynamically.
---
android/socket.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 4dcb5fc..c790c24 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -47,11 +47,9 @@
#define RFCOMM_CHANNEL_MAX 30
-#define SPP_DEFAULT_CHANNEL 3
-#define OPP_DEFAULT_CHANNEL 9
+#define OPP_DEFAULT_CHANNEL 12
#define HFAG_DEFAULT_CHANNEL 13
-#define PBAP_DEFAULT_CHANNEL 15
-#define MAS_DEFAULT_CHANNEL 16
+#define PBAP_DEFAULT_CHANNEL 19
#define SVC_HINT_OBEX 0x10
@@ -406,7 +404,7 @@ static const struct profile_info {
0x00, 0x00, 0x11, 0x32, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
- .channel = MAS_DEFAULT_CHANNEL,
+ .channel = 0,
.svc_hint = SVC_HINT_OBEX,
.sec_level = BT_IO_SEC_MEDIUM,
.create_record = create_mas_record
@@ -415,7 +413,7 @@ static const struct profile_info {
0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
- .channel = SPP_DEFAULT_CHANNEL,
+ .channel = 0,
.svc_hint = 0,
.sec_level = BT_IO_SEC_MEDIUM,
.create_record = create_spp_record
--
1.8.5.3
Records are now created using helper function which creates SDP record
with common contents like service class, name and protocols. Other
attributes are then added by custom functions.
---
android/socket.c | 281 ++++++++++++++++---------------------------------------
1 file changed, 80 insertions(+), 201 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 5045911..32de91a 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -180,18 +180,14 @@ static struct rfcomm_sock *create_rfsock(int bt_sock, int *hal_sock)
return rfsock;
}
-static sdp_record_t *create_opp_record(uint8_t chan, const char *svc_name)
+static sdp_record_t *create_rfcomm_record(uint8_t chan, uuid_t *uuid,
+ const char *svc_name,
+ bool has_obex)
{
- const char *service_name = "OBEX Object Push";
- sdp_list_t *svclass_id, *pfseq, *apseq, *root;
- uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
- sdp_profile_desc_t profile[1];
- sdp_list_t *aproto, *proto[3];
- 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_list_t *svclass_id;
+ sdp_list_t *seq, *proto_seq, *pbg_seq;
+ sdp_list_t *proto[2];
+ uuid_t l2cap_uuid, rfcomm_uuid, obex_uuid, pbg_uuid;
sdp_data_t *channel;
sdp_record_t *record;
@@ -201,267 +197,150 @@ static sdp_record_t *create_opp_record(uint8_t chan, const char *svc_name)
record->handle = sdp_next_handle();
- sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
- root = sdp_list_append(NULL, &root_uuid);
- sdp_set_browse_groups(record, root);
-
- sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
- svclass_id = sdp_list_append(NULL, &opush_uuid);
+ svclass_id = sdp_list_append(NULL, 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(NULL, profile);
- sdp_set_profile_descs(record, pfseq);
-
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
proto[0] = sdp_list_append(NULL, &l2cap_uuid);
- apseq = sdp_list_append(NULL, proto[0]);
+ seq = sdp_list_append(NULL, proto[0]);
sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
proto[1] = sdp_list_append(NULL, &rfcomm_uuid);
channel = sdp_data_alloc(SDP_UINT8, &chan);
proto[1] = sdp_list_append(proto[1], channel);
- apseq = sdp_list_append(apseq, proto[1]);
+ seq = sdp_list_append(seq, proto[1]);
- sdp_uuid16_create(&obex_uuid, OBEX_UUID);
- proto[2] = sdp_list_append(NULL, &obex_uuid);
- apseq = sdp_list_append(apseq, proto[2]);
+ if (has_obex) {
+ sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+ proto[2] = sdp_list_append(NULL, &obex_uuid);
+ seq = sdp_list_append(seq, proto[2]);
+ }
- aproto = sdp_list_append(NULL, apseq);
- sdp_set_access_protos(record, aproto);
+ proto_seq = sdp_list_append(NULL, seq);
+ sdp_set_access_protos(record, proto_seq);
- 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_uuid16_create(&pbg_uuid, PUBLIC_BROWSE_GROUP);
+ pbg_seq = sdp_list_append(NULL, &pbg_uuid);
+ sdp_set_browse_groups(record, pbg_seq);
if (svc_name)
- service_name = svc_name;
-
- sdp_set_info_attr(record, service_name, NULL, NULL);
+ sdp_set_info_attr(record, svc_name, NULL, NULL);
sdp_data_free(channel);
sdp_list_free(proto[0], NULL);
sdp_list_free(proto[1], NULL);
- sdp_list_free(proto[2], NULL);
- sdp_list_free(apseq, NULL);
- sdp_list_free(pfseq, NULL);
- sdp_list_free(aproto, NULL);
- sdp_list_free(root, NULL);
+ if (has_obex)
+ sdp_list_free(proto[2], NULL);
+ sdp_list_free(seq, NULL);
+ sdp_list_free(proto_seq, NULL);
+ sdp_list_free(pbg_seq, NULL);
sdp_list_free(svclass_id, NULL);
return record;
}
-static sdp_record_t *create_pbap_record(uint8_t chan, const char *svc_name)
+static sdp_record_t *create_opp_record(uint8_t chan, const char *svc_name)
{
- const char *service_name = "OBEX Phonebook Access Server";
- sdp_list_t *svclass_id, *pfseq, *apseq, *root;
- uuid_t root_uuid, pbap_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
- sdp_profile_desc_t profile[1];
- sdp_list_t *aproto, *proto[3];
- sdp_data_t *channel;
- uint8_t formats[] = { 0x01 };
+ uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
uint8_t dtd = SDP_UINT8;
- sdp_data_t *sflist;
+ uuid_t uuid;
+ sdp_list_t *seq;
+ sdp_profile_desc_t profile[1];
+ void *dtds[sizeof(formats)], *values[sizeof(formats)];
+ sdp_data_t *formats_list;
sdp_record_t *record;
+ size_t i;
- record = sdp_record_alloc();
+ sdp_uuid16_create(&uuid, OBEX_OBJPUSH_SVCLASS_ID);
+
+ record = create_rfcomm_record(chan, &uuid, svc_name, true);
if (!record)
return NULL;
- record->handle = sdp_next_handle();
-
- sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
- root = sdp_list_append(NULL, &root_uuid);
- sdp_set_browse_groups(record, root);
-
- sdp_uuid16_create(&pbap_uuid, PBAP_PSE_SVCLASS_ID);
- svclass_id = sdp_list_append(NULL, &pbap_uuid);
- sdp_set_service_classes(record, svclass_id);
-
- sdp_uuid16_create(&profile[0].uuid, PBAP_PROFILE_ID);
+ sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
profile[0].version = 0x0100;
- pfseq = sdp_list_append(NULL, profile);
- sdp_set_profile_descs(record, pfseq);
+ seq = sdp_list_append(NULL, profile);
+ sdp_set_profile_descs(record, seq);
- sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
- proto[0] = sdp_list_append(NULL, &l2cap_uuid);
- apseq = sdp_list_append(NULL, proto[0]);
+ for (i = 0; i < sizeof(formats); i++) {
+ dtds[i] = &dtd;
+ values[i] = &formats[i];
+ }
+ formats_list = sdp_seq_alloc(dtds, values, sizeof(formats));
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_FORMATS_LIST, formats_list);
- sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
- proto[1] = sdp_list_append(NULL, &rfcomm_uuid);
- channel = sdp_data_alloc(SDP_UINT8, &chan);
- proto[1] = sdp_list_append(proto[1], channel);
- apseq = sdp_list_append(apseq, proto[1]);
+ sdp_list_free(seq, NULL);
- sdp_uuid16_create(&obex_uuid, OBEX_UUID);
- proto[2] = sdp_list_append(NULL, &obex_uuid);
- apseq = sdp_list_append(apseq, proto[2]);
+ return record;
+}
- aproto = sdp_list_append(NULL, apseq);
- sdp_set_access_protos(record, aproto);
+static sdp_record_t *create_pbap_record(uint8_t chan, const char *svc_name)
+{
+ sdp_list_t *seq;
+ sdp_profile_desc_t profile[1];
+ uint8_t formats = 0x01;
+ sdp_record_t *record;
+ uuid_t uuid;
- sflist = sdp_data_alloc(dtd, formats);
- sdp_attr_add(record, SDP_ATTR_SUPPORTED_REPOSITORIES, sflist);
+ sdp_uuid16_create(&uuid, PBAP_PSE_SVCLASS_ID);
- if (svc_name)
- service_name = svc_name;
+ record = create_rfcomm_record(chan, &uuid, svc_name, true);
+ if (!record)
+ return NULL;
- sdp_set_info_attr(record, service_name, NULL, NULL);
+ sdp_uuid16_create(&profile[0].uuid, PBAP_PROFILE_ID);
+ profile[0].version = 0x0100;
+ seq = sdp_list_append(NULL, profile);
+ sdp_set_profile_descs(record, seq);
- sdp_data_free(channel);
- sdp_list_free(proto[0], NULL);
- sdp_list_free(proto[1], NULL);
- sdp_list_free(proto[2], 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);
+ sdp_attr_add_new(record, SDP_ATTR_SUPPORTED_REPOSITORIES, SDP_UINT8,
+ &formats);
+
+ sdp_list_free(seq, NULL);
return record;
}
static sdp_record_t *create_mas_record(uint8_t chan, const char *svc_name)
{
- const char *service_name = "MAP MAS SMS";
- sdp_list_t *svclass_id, *pfseq, *apseq, *root;
- uuid_t root_uuid, mse_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
+ sdp_list_t *seq;
sdp_profile_desc_t profile[1];
- sdp_list_t *aproto, *proto[3];
- sdp_data_t *channel;
uint8_t minst = DEFAULT_MAS_INSTANCE;
uint8_t mtype = DEFAULT_MAS_MSG_TYPE;
sdp_record_t *record;
+ uuid_t uuid;
- record = sdp_record_alloc();
+ sdp_uuid16_create(&uuid, MAP_MSE_SVCLASS_ID);
+
+ record = create_rfcomm_record(chan, &uuid, svc_name, true);
if (!record)
return NULL;
- record->handle = sdp_next_handle();
-
- sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
- root = sdp_list_append(NULL, &root_uuid);
- sdp_set_browse_groups(record, root);
-
- sdp_uuid16_create(&mse_uuid, MAP_MSE_SVCLASS_ID);
- svclass_id = sdp_list_append(NULL, &mse_uuid);
- sdp_set_service_classes(record, svclass_id);
-
sdp_uuid16_create(&profile[0].uuid, MAP_PROFILE_ID);
profile[0].version = 0x0101;
- pfseq = sdp_list_append(NULL, profile);
- sdp_set_profile_descs(record, pfseq);
+ seq = sdp_list_append(NULL, profile);
+ sdp_set_profile_descs(record, seq);
sdp_attr_add_new(record, SDP_ATTR_MAS_INSTANCE_ID, SDP_UINT8, &minst);
sdp_attr_add_new(record, SDP_ATTR_SUPPORTED_MESSAGE_TYPES, SDP_UINT8,
&mtype);
- sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
- proto[0] = sdp_list_append(NULL, &l2cap_uuid);
- apseq = sdp_list_append(NULL, proto[0]);
-
- sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
- proto[1] = sdp_list_append(NULL, &rfcomm_uuid);
- channel = sdp_data_alloc(SDP_UINT8, &chan);
- proto[1] = sdp_list_append(proto[1], channel);
- apseq = sdp_list_append(apseq, proto[1]);
-
- sdp_uuid16_create(&obex_uuid, OBEX_UUID);
- proto[2] = sdp_list_append(NULL, &obex_uuid);
- apseq = sdp_list_append(apseq, proto[2]);
-
- aproto = sdp_list_append(NULL, apseq);
- sdp_set_access_protos(record, aproto);
-
- if (svc_name)
- service_name = svc_name;
-
- sdp_set_info_attr(record, service_name, NULL, NULL);
-
- sdp_data_free(channel);
- sdp_list_free(proto[0], NULL);
- sdp_list_free(proto[1], NULL);
- sdp_list_free(proto[2], 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);
+ sdp_list_free(seq, NULL);
return record;
}
static sdp_record_t *create_spp_record(uint8_t chan, const char *svc_name)
{
- const char *service_name = "Serial Port";
- sdp_list_t *svclass_id, *apseq, *profiles, *root;
- uuid_t root_uuid, sp_uuid, l2cap, rfcomm;
- sdp_profile_desc_t profile;
- sdp_list_t *aproto, *proto[2];
- sdp_data_t *channel;
sdp_record_t *record;
+ uuid_t uuid;
- record = sdp_record_alloc();
+ sdp_uuid16_create(&uuid, SERIAL_PORT_SVCLASS_ID);
+
+ record = create_rfcomm_record(chan, &uuid, svc_name, false);
if (!record)
return NULL;
- record->handle = sdp_next_handle();
-
- sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
- root = sdp_list_append(NULL, &root_uuid);
- sdp_set_browse_groups(record, root);
-
- sdp_uuid16_create(&sp_uuid, SERIAL_PORT_SVCLASS_ID);
- svclass_id = sdp_list_append(NULL, &sp_uuid);
- sdp_set_service_classes(record, svclass_id);
-
- sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
- profile.version = 0x0100;
- profiles = sdp_list_append(NULL, &profile);
- sdp_set_profile_descs(record, profiles);
-
- sdp_uuid16_create(&l2cap, L2CAP_UUID);
- proto[0] = sdp_list_append(NULL, &l2cap);
- apseq = sdp_list_append(NULL, proto[0]);
-
- sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
- proto[1] = sdp_list_append(NULL, &rfcomm);
- channel = sdp_data_alloc(SDP_UINT8, &chan);
- proto[1] = sdp_list_append(proto[1], channel);
- apseq = sdp_list_append(apseq, proto[1]);
-
- aproto = sdp_list_append(NULL, apseq);
- sdp_set_access_protos(record, aproto);
-
- sdp_add_lang_attr(record);
-
- if (svc_name)
- service_name = svc_name;
-
- sdp_set_info_attr(record, service_name, "BlueZ", "COM Port");
-
- sdp_set_url_attr(record, "http://www.bluez.org/",
- "http://www.bluez.org/", "http://www.bluez.org/");
-
- sdp_set_service_id(record, sp_uuid);
- sdp_set_service_ttl(record, 0xffff);
- sdp_set_service_avail(record, 0xff);
- sdp_set_record_state(record, 0x00001234);
-
- sdp_data_free(channel);
- sdp_list_free(proto[0], NULL);
- sdp_list_free(proto[1], NULL);
- sdp_list_free(apseq, NULL);
- sdp_list_free(aproto, NULL);
- sdp_list_free(root, NULL);
- sdp_list_free(svclass_id, NULL);
- sdp_list_free(profiles, NULL);
-
return record;
}
--
1.8.5.3
This patch adds support to register server with channel number assigned
dynamically, i.e. first free number is assigned. Channels which are
reserved for built-in services are not assigned for other services.
---
android/socket.c | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 4e823dd..e560609 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -677,6 +677,21 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
new_rfsock->bt_watch = id;
}
+static int find_free_channel(void)
+{
+ int ch;
+
+ /* channel 0 is reserver so we don't use it */
+ for (ch = 1; ch <= RFCOMM_CHANNEL_MAX; ch++) {
+ struct rfcomm_channel *srv = &servers[ch];
+
+ if (!srv->reserved && srv->rfsock == NULL)
+ return ch;
+ }
+
+ return 0;
+}
+
static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
uint8_t flags, int *hal_sock)
{
@@ -704,15 +719,20 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
profile = get_profile_by_uuid(uuid);
if (!profile) {
- if (chan <= 0)
- return HAL_STATUS_INVALID;
-
sec_level = BT_IO_SEC_MEDIUM;
} else {
chan = profile->channel;
sec_level = profile->sec_level;
}
+ if (chan <= 0)
+ chan = find_free_channel();
+
+ if (!chan) {
+ error("No free channels");
+ return HAL_STATUS_BUSY;
+ }
+
if (servers[chan].rfsock != NULL) {
error("Channel already registered (%d)", chan);
return HAL_STATUS_BUSY;
--
1.8.5.3
This patch adds SDP record for services registered from application
(other than built-in services).
---
android/socket.c | 40 +++++++++++++++++++++++++++++++---------
1 file changed, 31 insertions(+), 9 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index e560609..9175bf3 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -350,6 +350,22 @@ static sdp_record_t *create_spp_record(uint8_t chan, const char *svc_name)
return record;
}
+static sdp_record_t *create_app_record(uint8_t chan,
+ const uint8_t *app_uuid,
+ const char *svc_name)
+{
+ sdp_record_t *record;
+ uuid_t uuid;
+
+ sdp_uuid128_create(&uuid, app_uuid);
+
+ record = create_rfcomm_record(chan, &uuid, svc_name, false);
+ if (!record)
+ return NULL;
+
+ return record;
+}
+
static const struct profile_info {
uint8_t uuid[16];
uint8_t channel;
@@ -396,19 +412,24 @@ static const struct profile_info {
},
};
-static uint32_t sdp_service_register(const struct profile_info *profile,
- const void *svc_name)
+static uint32_t sdp_service_register(uint8_t channel, const uint8_t *uuid,
+ const struct profile_info *profile,
+ const void *svc_name)
{
- sdp_record_t *record;
-
- if (!profile || !profile->create_record)
- return 0;
+ sdp_record_t *record = NULL;
+ uint8_t svc_hint = 0;
+
+ if (profile && profile->create_record) {
+ record = profile->create_record(channel, svc_name);
+ svc_hint = profile->svc_hint;
+ } else if (uuid) {
+ record = create_app_record(channel, uuid, svc_name);
+ }
- record = profile->create_record(profile->channel, svc_name);
if (!record)
return 0;
- if (bt_adapter_add_record(record, profile->svc_hint) < 0) {
+ if (bt_adapter_add_record(record, svc_hint) < 0) {
error("Failed to register on SDP record");
sdp_record_free(record);
return 0;
@@ -782,7 +803,8 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
goto failed;
}
- rfsock->service_handle = sdp_service_register(profile, name);
+ rfsock->service_handle = sdp_service_register(chan, uuid, profile,
+ name);
servers[chan].rfsock = rfsock;
--
1.8.5.3
Trying to listen on already assigned channel will now return busy
status instead of just fail.
---
android/android-tester.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/android/android-tester.c b/android/android-tester.c
index 870ad8d..9198514 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -2757,7 +2757,7 @@ static const struct socket_data btsock_inv_listen_listen = {
.service_uuid = NULL,
.service_name = "Test service",
.flags = 0,
- .expected_status = BT_STATUS_FAIL,
+ .expected_status = BT_STATUS_BUSY,
.test_channel = true,
};
--
1.8.5.3
This patch changes names of symbols related to various sockets to be
consistent and easier to follow in code.
Symbols related to actual BT (RFCOMM) socket are prefixed with "bt_".
Symbols related to local socket for Java comm are prefixed with "jv_".
Remote socket for Java comm is called "hal_sock".
---
android/socket.c | 186 ++++++++++++++++++++++++++++---------------------------
1 file changed, 95 insertions(+), 91 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 1375625..107042e 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -71,12 +71,15 @@ GList *servers = NULL;
GList *connections = NULL;
struct rfcomm_sock {
- int fd; /* descriptor for communication with Java framework */
- int real_sock; /* real RFCOMM socket */
int channel; /* RFCOMM channel */
- guint rfcomm_watch;
- guint stack_watch;
+ /* for socket to BT */
+ int bt_sock;
+ guint bt_watch;
+
+ /* for socket to HAL */
+ int jv_sock;
+ guint jv_watch;
bdaddr_t dst;
uint32_t service_handle;
@@ -92,13 +95,13 @@ static int rfsock_set_buffer(struct rfcomm_sock *rfsock)
socklen_t len = sizeof(int);
int rcv, snd, size, err;
- err = getsockopt(rfsock->real_sock, SOL_SOCKET, SO_RCVBUF, &rcv, &len);
+ err = getsockopt(rfsock->bt_sock, SOL_SOCKET, SO_RCVBUF, &rcv, &len);
if (err < 0) {
error("getsockopt(SO_RCVBUF): %s", strerror(errno));
return -errno;
}
- err = getsockopt(rfsock->real_sock, SOL_SOCKET, SO_SNDBUF, &snd, &len);
+ err = getsockopt(rfsock->bt_sock, SOL_SOCKET, SO_SNDBUF, &snd, &len);
if (err < 0) {
error("getsockopt(SO_SNDBUF): %s", strerror(errno));
return -errno;
@@ -118,25 +121,25 @@ static void cleanup_rfsock(gpointer data)
{
struct rfcomm_sock *rfsock = data;
- DBG("rfsock: %p fd %d real_sock %d chan %u",
- rfsock, rfsock->fd, rfsock->real_sock, rfsock->channel);
+ DBG("rfsock: %p jv_sock %d bt_sock %d chan %u",
+ rfsock, rfsock->jv_sock, rfsock->bt_sock, rfsock->channel);
- if (rfsock->fd >= 0)
- if (close(rfsock->fd) < 0)
- error("close() fd %d failed: %s", rfsock->fd,
+ if (rfsock->jv_sock >= 0)
+ if (close(rfsock->jv_sock) < 0)
+ error("close() fd %d failed: %s", rfsock->jv_sock,
strerror(errno));
- if (rfsock->real_sock >= 0)
- if (close(rfsock->real_sock) < 0)
- error("close() fd %d: failed: %s", rfsock->real_sock,
+ if (rfsock->bt_sock >= 0)
+ if (close(rfsock->bt_sock) < 0)
+ error("close() fd %d: failed: %s", rfsock->bt_sock,
strerror(errno));
- if (rfsock->rfcomm_watch > 0)
- if (!g_source_remove(rfsock->rfcomm_watch))
- error("rfcomm_watch source was not found");
+ if (rfsock->bt_watch > 0)
+ if (!g_source_remove(rfsock->bt_watch))
+ error("bt_watch source was not found");
- if (rfsock->stack_watch > 0)
- if (!g_source_remove(rfsock->stack_watch))
+ if (rfsock->jv_watch > 0)
+ if (!g_source_remove(rfsock->jv_watch))
error("stack_watch source was not found");
if (rfsock->service_handle)
@@ -148,23 +151,23 @@ static void cleanup_rfsock(gpointer data)
g_free(rfsock);
}
-static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
+static struct rfcomm_sock *create_rfsock(int bt_sock, int *hal_sock)
{
int fds[2] = {-1, -1};
struct rfcomm_sock *rfsock;
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
error("socketpair(): %s", strerror(errno));
- *hal_fd = -1;
+ *hal_sock = -1;
return NULL;
}
rfsock = g_new0(struct rfcomm_sock, 1);
- rfsock->fd = fds[0];
- *hal_fd = fds[1];
- rfsock->real_sock = sock;
+ rfsock->jv_sock = fds[0];
+ *hal_sock = fds[1];
+ rfsock->bt_sock = bt_sock;
- if (sock < 0)
+ if (bt_sock < 0)
return rfsock;
if (rfsock_set_buffer(rfsock) < 0) {
@@ -604,7 +607,7 @@ static int try_write_all(int fd, unsigned char *buf, int len)
return sent;
}
-static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
+static gboolean jv_sock_client_event_cb(GIOChannel *io, GIOCondition cond,
gpointer data)
{
struct rfcomm_sock *rfsock = data;
@@ -621,14 +624,14 @@ static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
goto fail;
}
- len = read(rfsock->fd, rfsock->buf, rfsock->buf_size);
+ len = read(rfsock->jv_sock, rfsock->buf, rfsock->buf_size);
if (len <= 0) {
error("read(): %s", strerror(errno));
/* Read again */
return TRUE;
}
- sent = try_write_all(rfsock->real_sock, rfsock->buf, len);
+ sent = try_write_all(rfsock->bt_sock, rfsock->buf, len);
if (sent < 0) {
error("write(): %s", strerror(errno));
goto fail;
@@ -642,7 +645,7 @@ fail:
return FALSE;
}
-static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
+static gboolean bt_sock_event_cb(GIOChannel *io, GIOCondition cond,
gpointer data)
{
struct rfcomm_sock *rfsock = data;
@@ -659,14 +662,14 @@ static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
goto fail;
}
- len = read(rfsock->real_sock, rfsock->buf, rfsock->buf_size);
+ len = read(rfsock->bt_sock, rfsock->buf, rfsock->buf_size);
if (len <= 0) {
error("read(): %s", strerror(errno));
/* Read again */
return TRUE;
}
- sent = try_write_all(rfsock->fd, rfsock->buf, len);
+ sent = try_write_all(rfsock->jv_sock, rfsock->buf, len);
if (sent < 0) {
error("write(): %s", strerror(errno));
goto fail;
@@ -693,7 +696,7 @@ static bool sock_send_accept(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr,
cmd.channel = rfsock->channel;
cmd.status = 0;
- len = bt_sock_send_fd(rfsock->fd, &cmd, sizeof(cmd), fd_accepted);
+ len = bt_sock_send_fd(rfsock->jv_sock, &cmd, sizeof(cmd), fd_accepted);
if (len != sizeof(cmd)) {
error("Error sending accept signal");
return false;
@@ -702,7 +705,7 @@ 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,
+static gboolean jv_sock_server_event_cb(GIOChannel *io, GIOCondition cond,
gpointer data)
{
struct rfcomm_sock *rfsock = data;
@@ -723,13 +726,13 @@ static gboolean sock_server_stack_event_cb(GIOChannel *io, GIOCondition cond,
static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
{
struct rfcomm_sock *rfsock = user_data;
- struct rfcomm_sock *rfsock_acc;
- GIOChannel *io_stack;
+ struct rfcomm_sock *new_rfsock;
+ GIOChannel *jv_io;
GError *gerr = NULL;
bdaddr_t dst;
char address[18];
- int sock_acc;
- int hal_fd;
+ int new_sock;
+ int hal_sock;
guint id;
GIOCondition cond;
@@ -751,51 +754,51 @@ static void accept_cb(GIOChannel *io, GError *err, gpointer user_data)
ba2str(&dst, address);
DBG("Incoming connection from %s rfsock %p", address, rfsock);
- sock_acc = g_io_channel_unix_get_fd(io);
- rfsock_acc = create_rfsock(sock_acc, &hal_fd);
- if (!rfsock_acc) {
+ new_sock = g_io_channel_unix_get_fd(io);
+ new_rfsock = create_rfsock(new_sock, &hal_sock);
+ if (!new_rfsock) {
g_io_channel_shutdown(io, TRUE, NULL);
return;
}
- DBG("rfsock: fd %d real_sock %d chan %u sock %d",
- rfsock->fd, rfsock->real_sock, rfsock->channel,
- sock_acc);
+ DBG("rfsock: jv_sock %d bt_sock %d chan %u new_sock %d",
+ rfsock->jv_sock, rfsock->bt_sock, rfsock->channel,
+ new_sock);
- if (!sock_send_accept(rfsock, &dst, hal_fd)) {
- cleanup_rfsock(rfsock_acc);
+ if (!sock_send_accept(rfsock, &dst, hal_sock)) {
+ cleanup_rfsock(new_rfsock);
return;
}
- connections = g_list_append(connections, rfsock_acc);
+ connections = g_list_append(connections, new_rfsock);
/* 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_acc->fd);
- id = g_io_add_watch(io_stack, cond, sock_stack_event_cb, rfsock_acc);
- g_io_channel_unref(io_stack);
+ jv_io = g_io_channel_unix_new(new_rfsock->jv_sock);
+ id = g_io_add_watch(jv_io, cond, jv_sock_client_event_cb, new_rfsock);
+ g_io_channel_unref(jv_io);
- rfsock_acc->stack_watch = id;
+ new_rfsock->jv_watch = id;
/* Handle rfcomm events */
cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
- id = g_io_add_watch(io, cond, sock_rfcomm_event_cb, rfsock_acc);
+ id = g_io_add_watch(io, cond, bt_sock_event_cb, new_rfsock);
g_io_channel_set_close_on_unref(io, FALSE);
- rfsock_acc->rfcomm_watch = id;
+ new_rfsock->bt_watch = id;
- DBG("rfsock %p rfsock_acc %p stack_watch %d rfcomm_watch %d",
- rfsock, rfsock_acc, rfsock_acc->stack_watch,
- rfsock_acc->rfcomm_watch);
+ DBG("rfsock %p rfsock_acc %p jv_watch %d bt_watch %d",
+ rfsock, new_rfsock, new_rfsock->jv_watch,
+ new_rfsock->bt_watch);
}
static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
- uint8_t flags, int *hal_fd)
+ uint8_t flags, int *hal_sock)
{
const struct profile_info *profile;
struct rfcomm_sock *rfsock = NULL;
BtIOSecLevel sec_level;
- GIOChannel *io, *io_stack;
+ GIOChannel *io, *jv_io;
GIOCondition cond;
GError *err = NULL;
guint id;
@@ -820,7 +823,7 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
DBG("rfcomm channel %d svc_name %s", chan, name);
- rfsock = create_rfsock(-1, hal_fd);
+ rfsock = create_rfsock(-1, hal_sock);
if (!rfsock)
return HAL_STATUS_FAILED;
@@ -835,25 +838,25 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
goto failed;
}
- rfsock->real_sock = g_io_channel_unix_get_fd(io);
+ rfsock->bt_sock = g_io_channel_unix_get_fd(io);
g_io_channel_set_close_on_unref(io, FALSE);
g_io_channel_unref(io);
/* Handle events from Android */
cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL;
- io_stack = g_io_channel_unix_new(rfsock->fd);
- id = g_io_add_watch_full(io_stack, G_PRIORITY_HIGH, cond,
- sock_server_stack_event_cb, rfsock,
+ jv_io = g_io_channel_unix_new(rfsock->jv_sock);
+ id = g_io_add_watch_full(jv_io, G_PRIORITY_HIGH, cond,
+ jv_sock_server_event_cb, rfsock,
NULL);
- g_io_channel_unref(io_stack);
+ g_io_channel_unref(jv_io);
- rfsock->stack_watch = id;
+ rfsock->jv_watch = id;
- DBG("real_sock %d fd %d hal_fd %d", rfsock->real_sock, rfsock->fd,
- *hal_fd);
+ DBG("bt_sock %d jv_sock %d hal_sock %d", rfsock->bt_sock,
+ rfsock->jv_sock, *hal_sock);
- if (write(rfsock->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+ if (write(rfsock->jv_sock, &chan, sizeof(chan)) != sizeof(chan)) {
error("Error sending RFCOMM channel");
goto failed;
}
@@ -867,7 +870,7 @@ static uint8_t rfcomm_listen(int chan, const uint8_t *name, const uint8_t *uuid,
failed:
cleanup_rfsock(rfsock);
- close(*hal_fd);
+ close(*hal_sock);
return HAL_STATUS_FAILED;
}
@@ -875,12 +878,12 @@ static void handle_listen(const void *buf, uint16_t len)
{
const struct hal_cmd_sock_listen *cmd = buf;
uint8_t status;
- int hal_fd;
+ int hal_sock;
switch (cmd->type) {
case HAL_SOCK_RFCOMM:
status = rfcomm_listen(cmd->channel, cmd->name, cmd->uuid,
- cmd->flags, &hal_fd);
+ cmd->flags, &hal_sock);
break;
case HAL_SOCK_SCO:
case HAL_SOCK_L2CAP:
@@ -895,8 +898,8 @@ static void handle_listen(const void *buf, uint16_t len)
goto failed;
ipc_send_rsp_full(HAL_SERVICE_ID_SOCK, HAL_OP_SOCK_LISTEN, 0, NULL,
- hal_fd);
- close(hal_fd);
+ hal_sock);
+ close(hal_sock);
return ;
failed:
@@ -916,7 +919,7 @@ static bool sock_send_connect(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr)
cmd.channel = rfsock->channel;
cmd.status = 0;
- len = write(rfsock->fd, &cmd, sizeof(cmd));
+ len = write(rfsock->jv_sock, &cmd, sizeof(cmd));
if (len < 0) {
error("%s", strerror(errno));
return false;
@@ -934,7 +937,7 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
struct rfcomm_sock *rfsock = user_data;
bdaddr_t *dst = &rfsock->dst;
- GIOChannel *io_stack;
+ GIOChannel *jv_io;
char address[18];
guint id;
GIOCondition cond;
@@ -947,8 +950,8 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
ba2str(dst, address);
DBG("Connected to %s", address);
- DBG("rfsock: fd %d real_sock %d chan %u sock %d",
- rfsock->fd, rfsock->real_sock, rfsock->channel,
+ DBG("rfsock: jv_sock %d bt_sock %d chan %u sock %d",
+ rfsock->jv_sock, rfsock->bt_sock, rfsock->channel,
g_io_channel_unix_get_fd(io));
if (!sock_send_connect(rfsock, dst))
@@ -956,18 +959,18 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
/* 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);
- id = g_io_add_watch(io_stack, cond, sock_stack_event_cb, rfsock);
- g_io_channel_unref(io_stack);
+ jv_io = g_io_channel_unix_new(rfsock->jv_sock);
+ id = g_io_add_watch(jv_io, cond, jv_sock_client_event_cb, rfsock);
+ g_io_channel_unref(jv_io);
- rfsock->stack_watch = id;
+ rfsock->jv_watch = id;
/* Handle rfcomm events */
cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- id = g_io_add_watch(io, cond, sock_rfcomm_event_cb, rfsock);
+ id = g_io_add_watch(io, cond, bt_sock_event_cb, rfsock);
g_io_channel_set_close_on_unref(io, FALSE);
- rfsock->rfcomm_watch = id;
+ rfsock->bt_watch = id;
return;
fail:
@@ -999,12 +1002,12 @@ static bool do_rfcomm_connect(struct rfcomm_sock *rfsock, int chan)
g_io_channel_set_close_on_unref(io, FALSE);
g_io_channel_unref(io);
- if (write(rfsock->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+ if (write(rfsock->jv_sock, &chan, sizeof(chan)) != sizeof(chan)) {
error("Error sending RFCOMM channel");
return false;
}
- rfsock->real_sock = g_io_channel_unix_get_fd(io);
+ rfsock->bt_sock = g_io_channel_unix_get_fd(io);
rfsock_set_buffer(rfsock);
rfsock->channel = chan;
connections = g_list_append(connections, rfsock);
@@ -1063,7 +1066,8 @@ fail:
}
static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
- const uint8_t *uuid, uint8_t flags, int *hal_fd)
+ const uint8_t *uuid, uint8_t flags,
+ int *hal_sock)
{
struct rfcomm_sock *rfsock;
uuid_t uu;
@@ -1074,7 +1078,7 @@ static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
return HAL_STATUS_INVALID;
}
- rfsock = create_rfsock(-1, hal_fd);
+ rfsock = create_rfsock(-1, hal_sock);
if (!rfsock)
return HAL_STATUS_FAILED;
@@ -1101,7 +1105,7 @@ static uint8_t connect_rfcomm(const bdaddr_t *addr, int chan,
failed:
cleanup_rfsock(rfsock);
- close(*hal_fd);
+ close(*hal_sock);
return HAL_STATUS_FAILED;
}
@@ -1110,7 +1114,7 @@ static void handle_connect(const void *buf, uint16_t len)
const struct hal_cmd_sock_connect *cmd = buf;
bdaddr_t bdaddr;
uint8_t status;
- int hal_fd;
+ int hal_sock;
DBG("");
@@ -1119,7 +1123,7 @@ static void handle_connect(const void *buf, uint16_t len)
switch (cmd->type) {
case HAL_SOCK_RFCOMM:
status = connect_rfcomm(&bdaddr, cmd->channel, cmd->uuid,
- cmd->flags, &hal_fd);
+ cmd->flags, &hal_sock);
break;
case HAL_SOCK_SCO:
case HAL_SOCK_L2CAP:
@@ -1134,8 +1138,8 @@ static void handle_connect(const void *buf, uint16_t len)
goto failed;
ipc_send_rsp_full(HAL_SERVICE_ID_SOCK, HAL_OP_SOCK_CONNECT, 0, NULL,
- hal_fd);
- close(hal_fd);
+ hal_sock);
+ close(hal_sock);
return;
failed:
--
1.8.5.3
It's now possible to add record with 128-bit UUID Service Class which
are used for custom applications. To simplify implementation adapter
uuids list stores now full UUID in uuid_t structure instead of uint16_t
short UUID.
---
android/bluetooth.c | 61 ++++++++++++++++++-----------------------------------
1 file changed, 21 insertions(+), 40 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 9f8e7b4..c064fe8 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1459,17 +1459,6 @@ static void load_link_keys(GSList *keys, bt_bluetooth_ready cb)
}
}
-/* output uint128 is in host order */
-static void uuid16_to_uint128(uint16_t uuid, uint128_t *u128)
-{
- uuid_t uuid16, uuid128;
-
- sdp_uuid16_create(&uuid16, uuid);
- sdp_uuid16_to_uuid128(&uuid128, &uuid16);
-
- ntoh128(&uuid128.value.uuid128, u128);
-}
-
static uint8_t get_adapter_uuids(void)
{
struct hal_ev_adapter_props_changed *ev;
@@ -1478,7 +1467,6 @@ static uint8_t get_adapter_uuids(void)
int len = uuid_count * sizeof(uint128_t);
uint8_t buf[BASELEN_PROP_CHANGED + len];
uint8_t *p;
- int i;
memset(buf, 0, sizeof(buf));
ev = (void *) buf;
@@ -1491,14 +1479,9 @@ static uint8_t get_adapter_uuids(void)
p = ev->props->val;
for (; list; list = g_slist_next(list)) {
- uint16_t uuid = GPOINTER_TO_UINT(list->data);
- uint128_t uint128;
-
- uuid16_to_uint128(uuid, &uint128);
+ uuid_t *uuid = list->data;
- /* Android expects swapped bytes in uuid */
- for (i = 0; i < 16; i++)
- p[15 - i] = uint128.data[i];
+ memcpy(p, &uuid->value.uuid128, sizeof(uint128_t));
p += sizeof(uint128_t);
}
@@ -1523,12 +1506,12 @@ static void remove_uuid_complete(uint8_t status, uint16_t length,
get_adapter_uuids();
}
-static void remove_uuid(uint16_t uuid)
+static void remove_uuid(uuid_t *uuid)
{
uint128_t uint128;
struct mgmt_cp_remove_uuid cp;
- uuid16_to_uint128(uuid, &uint128);
+ ntoh128((uint128_t *) uuid->value.uuid128.data, &uint128);
htob128(&uint128, (uint128_t *) cp.uuid);
mgmt_send(mgmt_if, MGMT_OP_REMOVE_UUID, adapter.index, sizeof(cp), &cp,
@@ -1549,14 +1532,14 @@ static void add_uuid_complete(uint8_t status, uint16_t length,
get_adapter_uuids();
}
-static void add_uuid(uint8_t svc_hint, uint16_t uuid)
+static void add_uuid(uint8_t svc_hint, uuid_t *uuid)
{
uint128_t uint128;
struct mgmt_cp_add_uuid cp;
- uuid16_to_uint128(uuid, &uint128);
-
+ ntoh128((uint128_t *) uuid->value.uuid128.data, &uint128);
htob128(&uint128, (uint128_t *) cp.uuid);
+
cp.svc_hint = svc_hint;
mgmt_send(mgmt_if, MGMT_OP_ADD_UUID, adapter.index, sizeof(cp), &cp,
@@ -1565,22 +1548,19 @@ static void add_uuid(uint8_t svc_hint, uint16_t uuid)
int bt_adapter_add_record(sdp_record_t *rec, uint8_t svc_hint)
{
- uint16_t uuid;
+ uuid_t *uuid;
- /* TODO support all types? */
- if (rec->svclass.type != SDP_UUID16) {
- warn("Ignoring unsupported UUID type");
- return -EINVAL;
- }
+ uuid = sdp_uuid_to_uuid128(&rec->svclass);
- uuid = rec->svclass.value.uuid16;
+ if (g_slist_find_custom(adapter.uuids, uuid, sdp_uuid_cmp)) {
+ char uuid_str[32];
- if (g_slist_find(adapter.uuids, GUINT_TO_POINTER(uuid))) {
- DBG("UUID 0x%x already added", uuid);
+ sdp_uuid2strn(uuid, uuid_str, sizeof(uuid_str));
+ DBG("UUID %s already added", uuid_str);
return -EALREADY;
}
- adapter.uuids = g_slist_prepend(adapter.uuids, GUINT_TO_POINTER(uuid));
+ adapter.uuids = g_slist_prepend(adapter.uuids, uuid);
add_uuid(svc_hint, uuid);
@@ -1591,20 +1571,21 @@ void bt_adapter_remove_record(uint32_t handle)
{
sdp_record_t *rec;
GSList *uuid_found;
- uint16_t uuid;
rec = sdp_record_find(handle);
if (!rec)
return;
- uuid = rec->svclass.value.uuid16;
-
- uuid_found = g_slist_find(adapter.uuids, GUINT_TO_POINTER(uuid));
+ uuid_found = g_slist_find_custom(adapter.uuids, &rec->svclass,
+ sdp_uuid_cmp);
if (uuid_found) {
+ uuid_t *uuid = uuid_found->data;
+
remove_uuid(uuid);
- adapter.uuids = g_slist_remove(adapter.uuids,
- uuid_found->data);
+ adapter.uuids = g_slist_remove(adapter.uuids, uuid);
+
+ free(uuid);
}
remove_record_from_server(handle);
--
1.8.5.3