From: Andrei Emeltchenko <[email protected]>
This is initial code implementing socket HAL. OPP currently works with send/receive files. Probaly
other profiles works as well, not tested yet.
Changes:
* v7: Rebase and fixing missing unref. All needed SDP records for supported profiles are created.
Support listen() with specified channel like in bluedroid.
* v6: Use watch_id to remove source and general cleanup
* v5: Changed uuid_to_chan table to profile table keeping information about profile like: channel, create_record,
svc_hint and sec_level.
* v4: Changed name rfslot -> rfsock following Johan's comment and other cosmetic changes, fixed one bug in SDP
record, use NULL instead of 0 for sdp functions.
* v3: Fixed coding style with write/send between file descriptors.
* v2: Following Marcel comments changed way copying between file descriptors works, added SDP record
for OPP and now it is possible to send files through GUI. Merged one patch with structures with actual user.
* v1: Rebased and use static src address, hal_fd removed from structure and closed after sent to framework,
added connect calls and SDP parsing, added cleanup_rfcomm function, minor fixes.
* RFC Initial
TODO:
* Use sec_level / check what to do with Android supplied security flags.
* Use splice() (requires bionic change first)
For tracking rfcomm sockets I use structure rfslot which has following
fields:
- real_sock - real RFCOMM socket
- fd - fd to communicate with Android framework
create_rfslot sets hal_fd which is fd passed to Android framework with CMSG
Andrei Emeltchenko (14):
android/socket: Parse SDP response and connect
android/socket: Implement HAL connect call
android/socket: Send RFCOMM channel to framework
android/socket: Send connect signal to Android framework
android/socket: Close file descriptor after sending
android/socket: Add general service create/remove function
android/socket: Add OPP SDP record
android/socket: Add MAS uuid to profile table
android/socket: Add SPP uuid to profile table
android/socket: Add PBAP SDP record
android/socket: Add SPP SDP record
android/socket: Support listen() with supplied chan number
android/hal-sock: Print bdaddr on connect
android/socket: Refactor socket send_fd function
android/hal-sock.c | 4 +-
android/socket.c | 418 +++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 408 insertions(+), 14 deletions(-)
--
1.8.3.2
On Fri, Nov 22, 2013 at 05:02:31PM +0200, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <[email protected]
this one merged to patch 1
Best regards
Andrei Emeltchenko
>
> ---
> android/socket.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/android/socket.c b/android/socket.c
> index 70e2307..7b9e41b 100644
> --- a/android/socket.c
> +++ b/android/socket.c
> @@ -852,6 +852,9 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
> sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free,
> NULL);
> sdp_list_free(protos, NULL);
> +
> + if (chan)
> + break;
> }
>
> if (chan <= 0) {
> --
> 1.8.3.2
>
> --
> 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
From: Andrei Emeltchenko <[email protected]>
---
android/socket.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index 70e2307..7b9e41b 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -852,6 +852,9 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free,
NULL);
sdp_list_free(protos, NULL);
+
+ if (chan)
+ break;
}
if (chan <= 0) {
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/socket.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 67 insertions(+), 1 deletion(-)
diff --git a/android/socket.c b/android/socket.c
index 5af0bf6..80afba5 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -251,6 +251,70 @@ static sdp_record_t *create_pbap_record(uint8_t chan, const char *svc_name)
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, rfcomm;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[1];
+ sdp_data_t *channel;
+ sdp_record_t *record;
+
+ record = sdp_record_alloc();
+ 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(&rfcomm, RFCOMM_UUID);
+ proto[0] = sdp_list_append(NULL, &rfcomm);
+ channel = sdp_data_alloc(SDP_UINT8, &chan);
+ proto[0] = sdp_list_append(proto[0], channel);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ 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(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;
+}
+
static struct profile_info {
uint8_t uuid[16];
uint8_t channel;
@@ -285,7 +349,9 @@ static struct profile_info {
0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
- .channel = SPP_DEFAULT_CHANNEL
+ .channel = SPP_DEFAULT_CHANNEL,
+ .svc_hint = 0,
+ .create_record = create_spp_record
},
};
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/socket.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/android/socket.c b/android/socket.c
index fa1aa3c..36f2f2e 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -45,6 +45,7 @@
#include "utils.h"
#include "socket.h"
+#define SPP_DEFAULT_CHANNEL 3
#define OPP_DEFAULT_CHANNEL 9
#define PBAP_DEFAULT_CHANNEL 15
#define MAS_DEFAULT_CHANNEL 16
@@ -212,7 +213,13 @@ static struct profile_info {
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
.channel = MAS_DEFAULT_CHANNEL
- }
+ }, {
+ .uuid = {
+ 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
+ },
+ .channel = SPP_DEFAULT_CHANNEL
+ },
};
static uint32_t sdp_service_register(struct profile_info *profile,
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
create_record function from profile is used to create SDP service record.
The record is removed from rfsock cleanup function.
---
android/socket.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 156a424..0c3964f 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -35,7 +35,9 @@
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
#include "src/sdp-client.h"
+#include "src/sdpd.h"
+#include "bluetooth.h"
#include "log.h"
#include "hal-msg.h"
#include "hal-ipc.h"
@@ -63,6 +65,7 @@ struct rfcomm_sock {
guint stack_watch;
bdaddr_t dst;
+ uint32_t service_handle;
};
static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
@@ -102,6 +105,9 @@ static void cleanup_rfsock(struct rfcomm_sock *rfsock)
if (!g_source_remove(rfsock->stack_watch))
error("stack_watch source was not found");
+ if (rfsock->service_handle)
+ bt_adapter_remove_record(rfsock->service_handle);
+
g_free(rfsock);
}
@@ -110,7 +116,7 @@ static struct profile_info {
uint8_t channel;
uint8_t svc_hint;
BtIOSecLevel sec_level;
- sdp_record_t * (*create_record)(uint8_t chan);
+ sdp_record_t * (*create_record)(uint8_t chan, const char *svc_name);
} profiles[] = {
{
.uuid = {
@@ -127,6 +133,24 @@ static struct profile_info {
}
};
+static uint32_t sdp_service_register(struct profile_info *profile,
+ const void *svc_name)
+{
+ sdp_record_t *record;
+
+ record = profile->create_record(profile->channel, svc_name);
+ if (!record)
+ return 0;
+
+ if (bt_adapter_add_record(record, profile->svc_hint) < 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;
@@ -388,7 +412,7 @@ static int handle_listen(void *buf)
chan = profile->channel;
- DBG("rfcomm channel %d", chan);
+ DBG("rfcomm channel %d svc_name %s", chan, cmd->name);
rfsock = create_rfsock(-1, &hal_fd);
if (!rfsock)
@@ -421,6 +445,8 @@ static int handle_listen(void *buf)
return -1;
}
+ rfsock->service_handle = sdp_service_register(profile, cmd->name);
+
return hal_fd;
}
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
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 | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 76 insertions(+), 1 deletion(-)
diff --git a/android/socket.c b/android/socket.c
index 0c3964f..a652a11 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -48,6 +48,8 @@
#define OPP_DEFAULT_CHANNEL 9
#define PBAP_DEFAULT_CHANNEL 15
+#define SVC_HINT_OBEX 0x10
+
static bdaddr_t adapter_addr;
/* Simple list of RFCOMM server sockets */
@@ -111,6 +113,77 @@ static void cleanup_rfsock(struct rfcomm_sock *rfsock)
g_free(rfsock);
}
+static sdp_record_t *create_opp_record(uint8_t chan, const char *svc_name)
+{
+ const char *service_name = "OBEX Object Push";
+ 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;
+
+ 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);
+ 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(&rfcomm_uuid, RFCOMM_UUID);
+ proto[0] = sdp_list_append(NULL, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &chan);
+ proto[0] = sdp_list_append(proto[0], channel);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+ proto[1] = sdp_list_append(NULL, &obex_uuid);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, 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);
+
+ 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(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;
+}
+
static struct profile_info {
uint8_t uuid[16];
uint8_t channel;
@@ -129,7 +202,9 @@ static struct profile_info {
0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
- .channel = OPP_DEFAULT_CHANNEL
+ .channel = OPP_DEFAULT_CHANNEL,
+ .svc_hint = SVC_HINT_OBEX,
+ .create_record = create_opp_record
}
};
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Parse SDP response, find RFCOMM channel and connect.
---
android/socket.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index 1815367..59cba67 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -424,9 +424,74 @@ 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_sock *rfsock = 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, 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_INVALID);
+ if (!io) {
+ error("Failed connect: %s", gerr->message);
+ g_error_free(gerr);
+ goto fail;
+ }
+
+ rfsock->real_sock = g_io_channel_unix_get_fd(io);
+ rfsock->channel = chan;
+ connections = g_list_append(connections, rfsock);
+
+ g_io_channel_unref(io);
+
+ return;
+fail:
+ cleanup_rfsock(rfsock);
}
static int handle_connect(void *buf)
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
HAL connect uses similar event handlers like listen call.
---
android/socket.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index 59cba67..37864e5 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -426,6 +426,42 @@ static int handle_listen(void *buf)
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;
+ char address[18];
+ guint id;
+ GIOCondition cond;
+
+ if (err) {
+ error("%s", err->message);
+ goto fail;
+ }
+
+ 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,
+ g_io_channel_unix_get_fd(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);
+ id = g_io_add_watch(io_stack, cond, sock_stack_event_cb, rfsock);
+ g_io_channel_unref(io_stack);
+
+ rfsock->stack_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);
+
+ rfsock->rfcomm_watch = id;
+
+ return;
+fail:
+ cleanup_rfsock(rfsock);
}
static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
No profile is assigned in this case. There is a possibility to use
Serial Port Profile.
---
android/socket.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 80afba5..dbd2012 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -629,10 +629,13 @@ static int handle_listen(void *buf)
DBG("");
profile = get_profile_by_uuid(cmd->uuid);
- if (!profile)
- return -1;
-
- chan = profile->channel;
+ if (!profile) {
+ if (!cmd->channel)
+ return -1;
+ else
+ chan = cmd->channel;
+ } else
+ chan = profile->channel;
DBG("rfcomm channel %d svc_name %s", chan, cmd->name);
@@ -667,7 +670,9 @@ static int handle_listen(void *buf)
return -1;
}
- rfsock->service_handle = sdp_service_register(profile, cmd->name);
+ if (profile)
+ rfsock->service_handle = sdp_service_register(profile,
+ cmd->name);
return hal_fd;
}
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
This adds SDP service record like shown below:
Service Name: OBEX Phonebook Access Server
Service RecHandle: 0x10002
Service Class ID List:
"Phonebook Access - PSE" (0x112f)
Protocol Descriptor List:
"RFCOMM" (0x0003)
Channel: 15
"OBEX" (0x0008)
Profile Descriptor List:
"Phonebook Access" (0x1130)
Version: 0x0100
---
android/socket.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 68 insertions(+), 1 deletion(-)
diff --git a/android/socket.c b/android/socket.c
index 36f2f2e..5af0bf6 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -186,6 +186,71 @@ static sdp_record_t *create_opp_record(uint8_t chan, const char *svc_name)
return record;
}
+static sdp_record_t *create_pbap_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, rfcomm_uuid, obex_uuid;
+ sdp_profile_desc_t profile[1];
+ sdp_list_t *aproto, *proto[2];
+ sdp_data_t *channel;
+ uint8_t formats[] = { 0x01 };
+ uint8_t dtd = SDP_UINT8;
+ sdp_data_t *sflist;
+ sdp_record_t *record;
+
+ record = sdp_record_alloc();
+ 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);
+ profile[0].version = 0x0100;
+ pfseq = sdp_list_append(NULL, profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[0] = sdp_list_append(NULL, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &chan);
+ proto[0] = sdp_list_append(proto[0], channel);
+ apseq = sdp_list_append(NULL, proto[0]);
+
+ sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+ proto[1] = sdp_list_append(NULL, &obex_uuid);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(NULL, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sflist = sdp_data_alloc(dtd, formats);
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_REPOSITORIES, sflist);
+
+ 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(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;
+}
+
static struct profile_info {
uint8_t uuid[16];
uint8_t channel;
@@ -198,7 +263,9 @@ static struct profile_info {
0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
},
- .channel = PBAP_DEFAULT_CHANNEL
+ .channel = PBAP_DEFAULT_CHANNEL,
+ .svc_hint = SVC_HINT_OBEX,
+ .create_record = create_pbap_record
}, {
.uuid = {
0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/socket.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index a652a11..fa1aa3c 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -47,6 +47,7 @@
#define OPP_DEFAULT_CHANNEL 9
#define PBAP_DEFAULT_CHANNEL 15
+#define MAS_DEFAULT_CHANNEL 16
#define SVC_HINT_OBEX 0x10
@@ -205,6 +206,12 @@ static struct profile_info {
.channel = OPP_DEFAULT_CHANNEL,
.svc_hint = SVC_HINT_OBEX,
.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
}
};
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
Make code cleaner and initialize local cmsg buffer to zeroes.
---
android/socket.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index dbd2012..daf4370 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -379,7 +379,7 @@ static int bt_sock_send_fd(int sock_fd, const void *buf, int len, int send_fd)
struct msghdr msg;
struct cmsghdr *cmsg;
struct iovec iv;
- char msgbuf[CMSG_SPACE(1)];
+ char cmsgbuf[CMSG_SPACE(sizeof(int))];
DBG("len %d sock_fd %d send_fd %d", len, sock_fd, send_fd);
@@ -387,13 +387,16 @@ static int bt_sock_send_fd(int sock_fd, const void *buf, int len, int send_fd)
return -1;
memset(&msg, 0, sizeof(msg));
+ memset(cmsgbuf, 0, sizeof(cmsgbuf));
+
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = sizeof(cmsgbuf);
- msg.msg_control = msgbuf;
- msg.msg_controllen = sizeof(msgbuf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd));
+
memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(send_fd));
iv.iov_base = (unsigned char *) buf;
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
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 37864e5..ab8d78b 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -519,6 +519,11 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
goto fail;
}
+ if (write(rfsock->fd, &chan, sizeof(chan)) != sizeof(chan)) {
+ error("Error sending RFCOMM channel");
+ goto fail;
+ }
+
rfsock->real_sock = g_io_channel_unix_get_fd(io);
rfsock->channel = chan;
connections = g_list_append(connections, rfsock);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/socket.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/android/socket.c b/android/socket.c
index 1691749..156a424 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -604,6 +604,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);
@@ -611,6 +612,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.8.3.2
From: Andrei Emeltchenko <[email protected]>
---
android/hal-sock.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/android/hal-sock.c b/android/hal-sock.c
index bd88ad8..e02a49a 100644
--- a/android/hal-sock.c
+++ b/android/hal-sock.c
@@ -82,8 +82,8 @@ static bt_status_t sock_connect(const bt_bdaddr_t *bdaddr, btsock_type_t type,
return BT_STATUS_PARM_INVALID;
}
- DBG("uuid %s chan %d sock %p type %d flags 0x%02x",
- btuuid2str(uuid), chan, sock, type, flags);
+ DBG("bdaddr %s uuid %s chan %d sock %p type %d flags 0x%02x",
+ bdaddr2str(bdaddr), btuuid2str(uuid), chan, sock, type, flags);
if (type != BTSOCK_RFCOMM) {
error("Socket type %u not supported", type);
--
1.8.3.2
From: Andrei Emeltchenko <[email protected]>
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 ab8d78b..1691749 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -424,6 +424,33 @@ static int handle_listen(void *buf)
return hal_fd;
}
+static bool sock_send_connect(struct rfcomm_sock *rfsock, bdaddr_t *bdaddr)
+{
+ struct hal_sock_connect_signal cmd;
+ int len;
+
+ DBG("");
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.size = sizeof(cmd);
+ bdaddr2android(bdaddr, cmd.bdaddr);
+ cmd.channel = rfsock->channel;
+ cmd.status = 0;
+
+ len = write(rfsock->fd, &cmd, sizeof(cmd));
+ if (len < 0) {
+ error("%s", strerror(errno));
+ return false;
+ }
+
+ if (len != sizeof(cmd)) {
+ error("Error sending connect signal");
+ return false;
+ }
+
+ return true;
+}
+
static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
struct rfcomm_sock *rfsock = user_data;
@@ -445,6 +472,9 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
rfsock->fd, rfsock->real_sock, rfsock->channel,
g_io_channel_unix_get_fd(io));
+ if (!sock_send_connect(rfsock, dst))
+ goto fail;
+
/* 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);
--
1.8.3.2