2015-02-12 17:00:05

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 0/3] shared/att: Add support to set security in LE link

It shall be possible to set security on the link once there is
such a requirement from remote server database.

Also as a server we should be able to get security level to determine
access to characteristics for remote client.

Those patches adds support to set/get security level.

Those patches are required in order to make Android code to use
shared/gatt-client

Note that if io is not L2CAP (e.g. unit test), set security level will always
succeed and get will always return BT_SECURITY_LOW for now.


Lukasz Rymanowski (3):
shared/att: Add set/get security level
shared/gatt-client: Expose API to set/get security level on att
tools/btgatt-client: Add support for set/get security on the link

src/shared/att.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/att.h | 3 ++
src/shared/gatt-client.c | 17 ++++++++++++
src/shared/gatt-client.h | 3 ++
tools/btgatt-client.c | 64 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 159 insertions(+)

--
1.8.4



2015-02-13 12:54:26

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 0/3] shared/att: Add support to set security in LE link

Hi Lukasz,

On Thu, Feb 12, 2015 at 7:00 PM, Lukasz Rymanowski
<[email protected]> wrote:
> It shall be possible to set security on the link once there is
> such a requirement from remote server database.
>
> Also as a server we should be able to get security level to determine
> access to characteristics for remote client.
>
> Those patches adds support to set/get security level.
>
> Those patches are required in order to make Android code to use
> shared/gatt-client
>
> Note that if io is not L2CAP (e.g. unit test), set security level will always
> succeed and get will always return BT_SECURITY_LOW for now.
>
>
> Lukasz Rymanowski (3):
> shared/att: Add set/get security level
> shared/gatt-client: Expose API to set/get security level on att
> tools/btgatt-client: Add support for set/get security on the link
>
> src/shared/att.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
> src/shared/att.h | 3 ++
> src/shared/gatt-client.c | 17 ++++++++++++
> src/shared/gatt-client.h | 3 ++
> tools/btgatt-client.c | 64 ++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 159 insertions(+)
>
> --
> 1.8.4

Applied, thanks.


--
Luiz Augusto von Dentz

2015-02-12 17:00:06

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 1/3] shared/att: Add set/get security level

---
src/shared/att.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/att.h | 3 +++
2 files changed, 75 insertions(+)

diff --git a/src/shared/att.c b/src/shared/att.c
index a98909e..d2468a0 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -57,6 +57,7 @@ struct bt_att {
int ref_count;
int fd;
struct io *io;
+ bool io_on_l2cap;

struct queue *req_queue; /* Queued ATT protocol requests */
struct att_send_op *pending_req;
@@ -774,6 +775,31 @@ static bool can_read_data(struct io *io, void *user_data)
return true;
}

+static bool is_io_l2cap_based(int fd)
+{
+ int domain;
+ int proto;
+ int err;
+ socklen_t len;
+
+ domain = 0;
+ len = sizeof(domain);
+ err = getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &domain, &len);
+ if (err < 0)
+ return false;
+
+ if (domain != AF_BLUETOOTH)
+ return false;
+
+ proto = 0;
+ len = sizeof(proto);
+ err = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &len);
+ if (err < 0)
+ return false;
+
+ return proto == BTPROTO_L2CAP;
+}
+
static void bt_att_free(struct bt_att *att)
{
if (att->pending_req)
@@ -849,6 +875,8 @@ struct bt_att *bt_att_new(int fd)
if (!io_set_disconnect_handler(att->io, disconnect_cb, att, NULL))
goto fail;

+ att->io_on_l2cap = is_io_l2cap_based(att->fd);
+
return bt_att_ref(att);

fail:
@@ -1226,3 +1254,47 @@ bool bt_att_unregister_all(struct bt_att *att)

return true;
}
+
+int bt_att_get_sec_level(struct bt_att *att)
+{
+ struct bt_security sec;
+ socklen_t len;
+
+ if (!att)
+ return -EINVAL;
+
+ /*
+ * Let's be nice for unit test.
+ * TODO: Might be needed to emulate different levels for test purposes
+ */
+ if (!att->io_on_l2cap)
+ return BT_SECURITY_LOW;
+
+ memset(&sec, 0, sizeof(sec));
+ len = sizeof(sec);
+ if (getsockopt(att->fd, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) < 0)
+ return -EIO;
+
+ return sec.level;
+}
+
+bool bt_att_set_sec_level(struct bt_att *att, int level)
+{
+ struct bt_security sec;
+
+ if (!att || level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH)
+ return false;
+
+ /* Let's be nice for unit test.*/
+ if (!att->io_on_l2cap)
+ return true;
+
+ memset(&sec, 0, sizeof(sec));
+ sec.level = level;
+
+ if (setsockopt(att->fd, SOL_BLUETOOTH, BT_SECURITY, &sec,
+ sizeof(sec)) < 0)
+ return false;
+
+ return true;
+}
diff --git a/src/shared/att.h b/src/shared/att.h
index cd00a1e..f13fc7b 100644
--- a/src/shared/att.h
+++ b/src/shared/att.h
@@ -79,3 +79,6 @@ unsigned int bt_att_register_disconnect(struct bt_att *att,
bool bt_att_unregister_disconnect(struct bt_att *att, unsigned int id);

bool bt_att_unregister_all(struct bt_att *att);
+
+int bt_att_get_sec_level(struct bt_att *att);
+bool bt_att_set_sec_level(struct bt_att *att, int level);
--
1.8.4


2015-02-12 17:00:08

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 3/3] tools/btgatt-client: Add support for set/get security on the link

---
tools/btgatt-client.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)

diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index 9416791..2d893c3 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -1072,6 +1072,66 @@ static void cmd_unregister_notify(struct client *cli, char *cmd_str)
printf("Unregistered notify handler with id: %u\n", id);
}

+static void set_sec_level_usage(void)
+{
+ printf("Usage: set_sec_level <level>\n"
+ "level: 1-3\n"
+ "e.g.:\n"
+ "\tset-sec-level 2\n");
+}
+
+static void cmd_set_sec_level(struct client *cli, char *cmd_str)
+{
+ char *argvbuf[1];
+ char **argv = argvbuf;
+ int argc = 0;
+ char *endptr = NULL;
+ int level;
+
+ if (!bt_gatt_client_is_ready(cli->gatt)) {
+ printf("GATT client not initialized\n");
+ return;
+ }
+
+ if (!parse_args(cmd_str, 1, argv, &argc)) {
+ printf("Too many arguments\n");
+ set_sec_level_usage();
+ return;
+ }
+
+ if (argc < 1) {
+ set_sec_level_usage();
+ return;
+ }
+
+ level = strtol(argv[0], &endptr, 0);
+ if (!endptr || *endptr != '\0' || level < 1 || level > 3) {
+ printf("Invalid level: %s\n", argv[0]);
+ return;
+ }
+
+ if (bt_gatt_client_set_sec_level(cli->gatt, level) < 0)
+ printf("Could not set sec level\n");
+ else
+ printf("Setting security level %d success\n", level);
+}
+
+static void cmd_get_sec_level(struct client *cli, char *cmd_str)
+{
+ int level;
+
+ if (!bt_gatt_client_is_ready(cli->gatt)) {
+ printf("GATT client not initialized\n");
+ return;
+ }
+
+ level = bt_gatt_client_get_sec_level(cli->gatt);
+ if (level < 0)
+ printf("Could not set sec level\n");
+ else
+ printf("Security level: %u\n", level);
+}
+
static void cmd_help(struct client *cli, char *cmd_str);

typedef void (*command_func_t)(struct client *cli, char *cmd_str);
@@ -1100,6 +1160,10 @@ static struct {
"\tSubscribe to not/ind from a characteristic" },
{ "unregister-notify", cmd_unregister_notify,
"Unregister a not/ind session"},
+ { "set-sec-level", cmd_set_sec_level,
+ "Set security level on le connection"},
+ { "get-sec-level", cmd_get_sec_level,
+ "Get security level on le connection"},
{ }
};

--
1.8.4


2015-02-12 17:00:07

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH 2/3] shared/gatt-client: Expose API to set/get security level on att

---
src/shared/gatt-client.c | 17 +++++++++++++++++
src/shared/gatt-client.h | 3 +++
2 files changed, 20 insertions(+)

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 293e0c2..d27354e 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -2854,3 +2854,20 @@ bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
complete_unregister_notify(notify_data);
return true;
}
+
+bool bt_gatt_client_set_sec_level(struct bt_gatt_client *client,
+ int level)
+{
+ if (!client)
+ return false;
+
+ return bt_att_set_sec_level(client->att, level);
+}
+
+int bt_gatt_client_get_sec_level(struct bt_gatt_client *client)
+{
+ if (!client)
+ return -1;
+
+ return bt_att_get_sec_level(client->att);
+}
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 46eb207..4346386 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -128,3 +128,6 @@ unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
bt_gatt_client_destroy_func_t destroy);
bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
unsigned int id);
+
+bool bt_gatt_client_set_sec_level(struct bt_gatt_client *client, int level);
+int bt_gatt_client_get_sec_level(struct bt_gatt_client *client);
--
1.8.4