* [PATCHv2 8/8] shared/hfp: Add function to get unquoted string
From: Marcin Kraglak @ 2014-02-27 9:40 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393494006-20363-1-git-send-email-marcin.kraglak@tieto.com>
---
src/shared/hfp.c | 28 ++++++++++++++++++++++++++++
src/shared/hfp.h | 2 ++
2 files changed, 30 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 5239fcd..2bed006 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -335,6 +335,34 @@ bool hfp_gw_result_get_string(struct hfp_gw_result *result, char *buf,
return true;
}
+bool hfp_gw_result_get_unquoted_string(struct hfp_gw_result *result, char *buf,
+ uint8_t len)
+{
+ const char *data = result->data;
+ int i = 0;
+ char c;
+
+ skip_whitespace(result);
+
+ c = data[result->offset];
+ if (c == '"' || c == ')' || c == '(')
+ return false;
+
+ while (data[result->offset] != '\0' && data[result->offset] != ','
+ && data[result->offset] != ')') {
+ if (i < len)
+ buf[i++] = data[result->offset];
+ result->offset++;
+ }
+
+ if (i < len)
+ buf[i++] = '\0';
+
+ next_field(result);
+
+ return true;
+}
+
static bool call_prefix_handler(struct hfp_gw *hfp, const char *data)
{
struct hfp_gw_result result;
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 4a69486..5148253 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -117,3 +117,5 @@ bool hfp_gw_result_open_container(struct hfp_gw_result *result);
bool hfp_gw_result_close_container(struct hfp_gw_result *result);
bool hfp_gw_result_get_string(struct hfp_gw_result *result, char *buf,
uint8_t len);
+bool hfp_gw_result_get_unquoted_string(struct hfp_gw_result *result, char *buf,
+ uint8_t len);
--
1.8.3.1
^ permalink raw reply related
* [PATCHv2 7/8] shared/hfp: Add function to get string
From: Marcin Kraglak @ 2014-02-27 9:40 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393494006-20363-1-git-send-email-marcin.kraglak@tieto.com>
It will look for quoted sting and write it to given buffer.
---
src/shared/hfp.c | 33 +++++++++++++++++++++++++++++++++
src/shared/hfp.h | 2 ++
2 files changed, 35 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index abecb31..5239fcd 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -302,6 +302,39 @@ bool hfp_gw_result_close_container(struct hfp_gw_result *result)
return true;
}
+bool hfp_gw_result_get_string(struct hfp_gw_result *result, char *buf,
+ uint8_t len)
+{
+ int i = 0;
+ const char *data = result->data;
+
+ skip_whitespace(result);
+
+ if (data[result->offset] != '"')
+ return false;
+
+ result->offset++;
+
+ while (data[result->offset] != '\0' && data[result->offset] != '"') {
+ if (i < len)
+ buf[i++] = data[result->offset];
+ result->offset++;
+ }
+
+ if (i < len)
+ buf[i++] = '\0';
+
+ if (data[result->offset] == '"')
+ result->offset++;
+ else
+ return false;
+
+ skip_whitespace(result);
+ next_field(result);
+
+ return true;
+}
+
static bool call_prefix_handler(struct hfp_gw *hfp, const char *data)
{
struct hfp_gw_result result;
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 5ad214d..4a69486 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -115,3 +115,5 @@ bool hfp_gw_remove_prefix_handler(struct hfp_gw *hfp, char *prefix);
bool hfp_gw_result_get_number(struct hfp_gw_result *result, int *val);
bool hfp_gw_result_open_container(struct hfp_gw_result *result);
bool hfp_gw_result_close_container(struct hfp_gw_result *result);
+bool hfp_gw_result_get_string(struct hfp_gw_result *result, char *buf,
+ uint8_t len);
--
1.8.3.1
^ permalink raw reply related
* [PATCHv2 6/8] shared/hfp: Add open/close container function
From: Marcin Kraglak @ 2014-02-27 9:40 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393494006-20363-1-git-send-email-marcin.kraglak@tieto.com>
It will look for "(" or ")" parenthesis and skip it if found.
---
src/shared/hfp.c | 26 ++++++++++++++++++++++++++
src/shared/hfp.h | 2 ++
2 files changed, 28 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index f4cf3a4..abecb31 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -276,6 +276,32 @@ bool hfp_gw_result_get_number(struct hfp_gw_result *result, int *val)
return true;
}
+bool hfp_gw_result_open_container(struct hfp_gw_result *result)
+{
+ skip_whitespace(result);
+
+ /* The list shall be preceded by a left parenthesis "(") */
+ if (result->data[result->offset] != '(')
+ return false;
+
+ result->offset++;
+
+ return true;
+}
+
+bool hfp_gw_result_close_container(struct hfp_gw_result *result)
+{
+ skip_whitespace(result);
+
+ /* The list shall be followed by a right parenthesis (")" V250 5.7.3.1*/
+ if (result->data[result->offset] != ')')
+ return false;
+
+ result->offset++;
+
+ return true;
+}
+
static bool call_prefix_handler(struct hfp_gw *hfp, const char *data)
{
struct hfp_gw_result result;
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 7642b7c..5ad214d 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -113,3 +113,5 @@ bool hfp_gw_set_prefix_handler(struct hfp_gw *hfp, hfp_result_func_t callback,
bool hfp_gw_remove_prefix_handler(struct hfp_gw *hfp, char *prefix);
bool hfp_gw_result_get_number(struct hfp_gw_result *result, int *val);
+bool hfp_gw_result_open_container(struct hfp_gw_result *result);
+bool hfp_gw_result_close_container(struct hfp_gw_result *result);
--
1.8.3.1
^ permalink raw reply related
* [PATCHv2 5/8] shared/hfp: Add get_number implementation
From: Marcin Kraglak @ 2014-02-27 9:40 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393494006-20363-1-git-send-email-marcin.kraglak@tieto.com>
User can call this function with hfp_gw_result, which will
be passed to prefix handler.
---
src/shared/hfp.c | 33 +++++++++++++++++++++++++++++++++
src/shared/hfp.h | 2 ++
2 files changed, 35 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 6a39a36..f4cf3a4 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -237,12 +237,45 @@ static bool process_extended(struct hfp_gw *hfp, struct hfp_gw_result *result)
return true;
}
+static void next_field(struct hfp_gw_result *result)
+{
+ if (result->data[result->offset] == ',')
+ result->offset++;
+}
+
static void skip_whitespace(struct hfp_gw_result *result)
{
while (result->data[result->offset] == ' ')
result->offset++;
}
+bool hfp_gw_result_get_number(struct hfp_gw_result *result, int *val)
+{
+ int temp = 0;
+ int i;
+
+ skip_whitespace(result);
+
+ i = result->offset;
+
+ while (result->data[i] >= '0' && result->data[i] <= '9') {
+ temp *= 10;
+ temp += result->data[i++] - '0';
+ }
+
+ if (i == result->offset)
+ return false;
+
+ if (val)
+ *val = temp;
+ result->offset = i;
+
+ skip_whitespace(result);
+ next_field(result);
+
+ return true;
+}
+
static bool call_prefix_handler(struct hfp_gw *hfp, const char *data)
{
struct hfp_gw_result result;
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 306824d..7642b7c 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -111,3 +111,5 @@ bool hfp_gw_set_prefix_handler(struct hfp_gw *hfp, hfp_result_func_t callback,
char *prefix, void *user_data,
hfp_destroy_func_t destroy);
bool hfp_gw_remove_prefix_handler(struct hfp_gw *hfp, char *prefix);
+
+bool hfp_gw_result_get_number(struct hfp_gw_result *result, int *val);
--
1.8.3.1
^ permalink raw reply related
* [PATCHv2 4/8] shared/hfp: Add implementation of precessing commands
From: Marcin Kraglak @ 2014-02-27 9:40 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393494006-20363-1-git-send-email-marcin.kraglak@tieto.com>
It will process both extended and basic commands.
---
src/shared/hfp.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 94 insertions(+), 2 deletions(-)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index cf54a8f..6a39a36 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
+#include <ctype.h>
#include "src/shared/util.h"
#include "src/shared/ringbuf.h"
@@ -135,14 +136,105 @@ static void wakeup_writer(struct hfp_gw *hfp)
hfp->writer_active = true;
}
+static enum hfp_cmd_type get_cmd_type(struct hfp_gw_result *result)
+{
+ if (result->data[result->offset] == '=') {
+ result->offset++;
+ if (result->data[result->offset] == '?') {
+ result->offset++;
+ return HFP_AT_TEST;
+ } else {
+ return HFP_AT_SET;
+ }
+ } else if (result->data[result->offset] == '?') {
+ result->offset++;
+ return HFP_AT_READ;
+ } else {
+ return HFP_AT_COMMAND;
+ }
+}
+
static bool process_basic(struct hfp_gw *hfp, struct hfp_gw_result *result)
{
- return false;
+ const char *prefix = result->data + result->offset;
+ struct prefix_handler_data *handler;
+ enum hfp_cmd_type type;
+ char lookup_prefix[4];
+ uint8_t pref_len = 0;
+ int i;
+
+ /* Check if first sign is character */
+ if (isalpha(prefix[pref_len])) {
+ /* Handle S-parameter prefix */
+ if (toupper(prefix[pref_len]) == 'S') {
+ do {
+ pref_len++;
+ } while (isdigit(prefix[pref_len]));
+ /*S-parameter must be followed with number*/
+ if (pref_len == 1)
+ pref_len--;
+ } else {
+ /* It's just one-character prefix */
+ pref_len++;
+ }
+ }
+
+ if (pref_len == 0 || pref_len > sizeof(lookup_prefix))
+ return false;
+
+ for (i = 0; i < pref_len; i++)
+ lookup_prefix[i] = toupper(prefix[i]);
+
+ result->offset += pref_len;
+ lookup_prefix[pref_len] = '\0';
+
+ if (lookup_prefix[0] == 'D')
+ type = HFP_AT_SET;
+ else
+ type = get_cmd_type(result);
+
+ handler = queue_find(hfp->prefix_handlers, match_handler_prefix,
+ lookup_prefix);
+ if (!handler)
+ return false;
+
+ handler->callback(result, type, handler->user_data);
+
+ return true;
}
static bool process_extended(struct hfp_gw *hfp, struct hfp_gw_result *result)
{
- return false;
+ const char *prefix = result->data + result->offset;
+ const char *separators = ";?=\0";
+ struct prefix_handler_data *handler;
+ enum hfp_cmd_type type;
+ char lookup_prefix[18];
+ uint8_t pref_len;
+ int i;
+
+ /* Lookup for first separator */
+ pref_len = strcspn(prefix, separators);
+
+ if (pref_len > 17 || pref_len < 2)
+ return false;
+
+ for (i = 0; i < pref_len; i++)
+ lookup_prefix[i] = toupper(prefix[i]);
+
+ result->offset += pref_len;
+ lookup_prefix[pref_len] = '\0';
+
+ type = get_cmd_type(result);
+
+ handler = queue_find(hfp->prefix_handlers, match_handler_prefix,
+ lookup_prefix);
+ if (!handler)
+ return false;
+
+ handler->callback(result, type, handler->user_data);
+
+ return true;
}
static void skip_whitespace(struct hfp_gw_result *result)
--
1.8.3.1
^ permalink raw reply related
* [PATCHv2 3/8] shared/hfp: Add initial implementiation of processing commands
From: Marcin Kraglak @ 2014-02-27 9:40 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393494006-20363-1-git-send-email-marcin.kraglak@tieto.com>
---
src/shared/hfp.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 51 insertions(+), 4 deletions(-)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index e164dd6..cf54a8f 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -69,6 +69,11 @@ struct prefix_handler_data {
hfp_result_func_t callback;
};
+struct hfp_gw_result {
+ const char *data;
+ int offset;
+};
+
static void destroy_prefix_handler_data(void *data)
{
struct prefix_handler_data *handler = data;
@@ -130,6 +135,46 @@ static void wakeup_writer(struct hfp_gw *hfp)
hfp->writer_active = true;
}
+static bool process_basic(struct hfp_gw *hfp, struct hfp_gw_result *result)
+{
+ return false;
+}
+
+static bool process_extended(struct hfp_gw *hfp, struct hfp_gw_result *result)
+{
+ return false;
+}
+
+static void skip_whitespace(struct hfp_gw_result *result)
+{
+ while (result->data[result->offset] == ' ')
+ result->offset++;
+}
+
+static bool call_prefix_handler(struct hfp_gw *hfp, const char *data)
+{
+ struct hfp_gw_result result;
+
+ result.offset = 0;
+ result.data = data;
+
+ skip_whitespace(&result);
+
+ if (strlen(data + result.offset) < 3)
+ return false;
+
+ if (strncmp(data + result.offset, "AT", 2))
+ if (strncmp(data + result.offset, "at", 2))
+ return false;
+
+ result.offset += 2;
+
+ if (data[result.offset] == '+')
+ return process_extended(hfp, &result);
+ else
+ return process_basic(hfp, &result);
+}
+
static void process_input(struct hfp_gw *hfp)
{
char *str, *ptr;
@@ -163,10 +208,12 @@ static void process_input(struct hfp_gw *hfp)
len = ringbuf_drain(hfp->read_buf, count + 1);
- if (hfp->command_callback)
- hfp->command_callback(ptr, hfp->command_data);
- else
- hfp_gw_send_result(hfp, HFP_RESULT_ERROR);
+ if (!call_prefix_handler(hfp, ptr)) {
+ if (hfp->command_callback)
+ hfp->command_callback(ptr, hfp->command_data);
+ else
+ hfp_gw_send_result(hfp, HFP_RESULT_ERROR);
+ }
free(ptr);
}
--
1.8.3.1
^ permalink raw reply related
* [PATCHv2 2/8] shared/hfp: Add prefix handlers functionality
From: Marcin Kraglak @ 2014-02-27 9:40 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393494006-20363-1-git-send-email-marcin.kraglak@tieto.com>
Add two functions: hfp_gw_set_prefix_handler() and
hfp_gw_remove_prefix_handler(). It will allow user to register for
specific command. Current implementation just adds or removes data
from hfp_gw structure.
---
Makefile.tools | 1 +
src/shared/hfp.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/hfp.h | 17 ++++++++++++
3 files changed, 102 insertions(+)
diff --git a/Makefile.tools b/Makefile.tools
index 9f7ba9f..31e1093 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -63,6 +63,7 @@ emulator_hfp_SOURCES = emulator/hfp.c \
monitor/mainloop.h monitor/mainloop.c \
src/shared/io.h src/shared/io-mainloop.c \
src/shared/util.h src/shared/util.c \
+ src/shared/queue.h src/shared/queue.c \
src/shared/ringbuf.h src/shared/ringbuf.c \
src/shared/hfp.h src/shared/hfp.c
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 0681b19..e164dd6 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -32,6 +32,7 @@
#include "src/shared/util.h"
#include "src/shared/ringbuf.h"
+#include "src/shared/queue.h"
#include "src/shared/io.h"
#include "src/shared/hfp.h"
@@ -42,6 +43,7 @@ struct hfp_gw {
struct io *io;
struct ringbuf *read_buf;
struct ringbuf *write_buf;
+ struct queue *prefix_handlers;
bool writer_active;
bool permissive_syntax;
bool result_pending;
@@ -60,6 +62,37 @@ struct hfp_gw {
bool destroyed;
};
+struct prefix_handler_data {
+ char *prefix;
+ void *user_data;
+ hfp_destroy_func_t destroy;
+ hfp_result_func_t callback;
+};
+
+static void destroy_prefix_handler_data(void *data)
+{
+ struct prefix_handler_data *handler = data;
+
+ if (handler->destroy)
+ handler->destroy(handler->user_data);
+
+ free(handler);
+}
+
+static bool match_handler_prefix(const void *a, const void *b)
+{
+ const struct prefix_handler_data *handler = a;
+ const char *prefix = b;
+
+ if (strlen(handler->prefix) != strlen(prefix))
+ return false;
+
+ if (memcmp(handler->prefix, prefix, strlen(prefix)))
+ return false;
+
+ return true;
+}
+
static void write_watch_destroy(void *user_data)
{
struct hfp_gw *hfp = user_data;
@@ -194,8 +227,19 @@ struct hfp_gw *hfp_gw_new(int fd)
return NULL;
}
+ hfp->prefix_handlers = queue_new();
+ if (!hfp->prefix_handlers) {
+ io_destroy(hfp->io);
+ ringbuf_free(hfp->write_buf);
+ ringbuf_free(hfp->read_buf);
+ free(hfp);
+ return NULL;
+ }
+
if (!io_set_read_handler(hfp->io, can_read_data,
hfp, read_watch_destroy)) {
+ queue_destroy(hfp->prefix_handlers,
+ destroy_prefix_handler_data);
io_destroy(hfp->io);
ringbuf_free(hfp->write_buf);
ringbuf_free(hfp->read_buf);
@@ -248,6 +292,9 @@ void hfp_gw_unref(struct hfp_gw *hfp)
ringbuf_free(hfp->write_buf);
hfp->write_buf = NULL;
+ queue_destroy(hfp->prefix_handlers, destroy_prefix_handler_data);
+ hfp->prefix_handlers = NULL;
+
if (!hfp->in_disconnect) {
free(hfp);
return;
@@ -407,6 +454,43 @@ bool hfp_gw_set_command_handler(struct hfp_gw *hfp,
return true;
}
+bool hfp_gw_set_prefix_handler(struct hfp_gw *hfp, hfp_result_func_t callback,
+ char *prefix, void *user_data,
+ hfp_destroy_func_t destroy)
+{
+ struct prefix_handler_data *handler;
+
+ handler = queue_find(hfp->prefix_handlers, match_handler_prefix,
+ prefix);
+ if (handler)
+ return false;
+
+ handler = new0(struct prefix_handler_data, 1);
+ if (!handler)
+ return false;
+
+ handler->callback = callback;
+ handler->prefix = prefix;
+ handler->destroy = destroy;
+ handler->user_data = user_data;
+
+ return queue_push_tail(hfp->prefix_handlers, handler);
+}
+
+bool hfp_gw_remove_prefix_handler(struct hfp_gw *hfp, char *prefix)
+{
+ struct prefix_handler_data *handler;
+
+ handler = queue_remove_if(hfp->prefix_handlers, match_handler_prefix,
+ prefix);
+ if (!handler)
+ return false;
+
+ destroy_prefix_handler_data(handler);
+
+ return true;
+}
+
static void disconnect_watch_destroy(void *user_data)
{
struct hfp_gw *hfp = user_data;
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index b0bd934..306824d 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -60,6 +60,18 @@ enum hfp_error {
HFP_ERROR_NETWORK_NOT_ALLOWED = 32,
};
+enum hfp_cmd_type {
+ HFP_AT_READ,
+ HFP_AT_SET,
+ HFP_AT_TEST,
+ HFP_AT_COMMAND
+};
+
+struct hfp_gw_result;
+
+typedef void (*hfp_result_func_t)(struct hfp_gw_result *result,
+ enum hfp_cmd_type type, void *user_data);
+
typedef void (*hfp_destroy_func_t)(void *user_data);
typedef void (*hfp_debug_func_t)(const char *str, void *user_data);
@@ -94,3 +106,8 @@ bool hfp_gw_set_disconnect_handler(struct hfp_gw *hfp,
hfp_destroy_func_t destroy);
bool hfp_gw_disconnect(struct hfp_gw *hfp);
+
+bool hfp_gw_set_prefix_handler(struct hfp_gw *hfp, hfp_result_func_t callback,
+ char *prefix, void *user_data,
+ hfp_destroy_func_t destroy);
+bool hfp_gw_remove_prefix_handler(struct hfp_gw *hfp, char *prefix);
--
1.8.3.1
^ permalink raw reply related
* [PATCHv2 1/8] shared/hfp: Fix parsing line with few commands
From: Marcin Kraglak @ 2014-02-27 9:39 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393494006-20363-1-git-send-email-marcin.kraglak@tieto.com>
If hfp_gw received line with few commands, it called command
handler one time, for first command. Next comamnd was processed
only if next line was received.
Now, after every response from gw, we call proces_input to be
sure that all data has been be processed.
It will process next command only if response for previous was sent.
---
src/shared/hfp.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 854cf46..0681b19 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -121,23 +121,21 @@ static void process_input(struct hfp_gw *hfp)
*ptr = '\0';
count = asprintf(&ptr, "%s%s", str, str2);
- str = ptr;
} else {
- count = ptr - str;
*ptr = '\0';
+ count = asprintf(&ptr, "%s", str);
}
hfp->result_pending = true;
+ len = ringbuf_drain(hfp->read_buf, count + 1);
+
if (hfp->command_callback)
- hfp->command_callback(str, hfp->command_data);
+ hfp->command_callback(ptr, hfp->command_data);
else
hfp_gw_send_result(hfp, HFP_RESULT_ERROR);
- len = ringbuf_drain(hfp->read_buf, count + 1);
-
- if (str == ptr)
- free(ptr);
+ free(ptr);
}
static void read_watch_destroy(void *user_data)
@@ -341,6 +339,8 @@ bool hfp_gw_send_result(struct hfp_gw *hfp, enum hfp_result result)
hfp->result_pending = false;
+ process_input(hfp);
+
return true;
}
@@ -356,6 +356,8 @@ bool hfp_gw_send_error(struct hfp_gw *hfp, enum hfp_error error)
hfp->result_pending = false;
+ process_input(hfp);
+
return true;
}
--
1.8.3.1
^ permalink raw reply related
* [PATCHv2 0/8] HFP_GW parser
From: Marcin Kraglak @ 2014-02-27 9:39 UTC (permalink / raw)
To: linux-bluetooth
v2:
- parser moved to src/shared/hfp
- dynamic register/unregister prefix handlers
- minor fixes pointed by Marcel
Marcin Kraglak (8):
shared/hfp: Fix parsing line with few commands
shared/hfp: Add prefix handlers functionality
shared/hfp: Add initial implementiation of processing commands
shared/hfp: Add implementation of precessing commands
shared/hfp: Add get_number implementation
shared/hfp: Add open/close container function
shared/hfp: Add function to get string
shared/hfp: Add function to get unquoted string
Makefile.tools | 1 +
src/shared/hfp.c | 363 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
src/shared/hfp.h | 25 ++++
3 files changed, 380 insertions(+), 9 deletions(-)
--
1.8.3.1
^ permalink raw reply
* Re: [PATCH] tty: Fix low_latency BUG
From: One Thousand Gnomes @ 2014-02-27 9:22 UTC (permalink / raw)
To: Feng Tang
Cc: Peter Hurley, Greg Kroah-Hartman, Jiri Slaby, linux-serial,
Beat Bolli, Pavel Roskin, Linux Kernel Mailing List, Jiri Kosina,
David Sterba, Felipe Balbi, Grant Edwards, Stanislaw Gruszka,
Hal Murray, stable, linux-bluetooth, feng.tang, bin.yang, alek.du
In-Reply-To: <CA++bM2vjzFOt5wmc=TQ1XMvRCwgnpq6=PKpex=GGZBK_-M6=mw@mail.gmail.com>
> > I'm glad to hear that the Bluetooth uart interface is getting
> > some use; that means someone will soon be fixing the hard lockup
> > in hci_uart_tx_wakeup() reported here:
>
> I'm not very familiar with the BT devices on our platforms, but most
> of them are not using the in-kernel BT driver, some just use the
> n_tty ldisc and the raw data, some use their own ldisc driver.
Outside of the world of phones/android the Bluetooth on quite a few of the
Baytrail/T devices is on the LPSS serial so it probably will be getting
tested sooner not later and there will actually be a common platform
around that is using the bluetooth uart features.
I'm not anticipating any problems though.
Alan
^ permalink raw reply
* [PATCH 5/5] unit/avrcp: Add /TP/PAS/BV-01-C test
From: Andrei Emeltchenko @ 2014-02-27 9:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393492291-15099-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that the List Player Application Setting Attributes command
issued from the Controller.
---
unit/test-avrcp.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 0924a7e..c65f743 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -358,6 +358,9 @@ static void test_client(gconstpointer data)
avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED,
NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/PAS/BV-01-C"))
+ avrcp_list_player_attributes(context->session, NULL, NULL);
+
execute_context(context);
}
@@ -452,5 +455,12 @@ int main(int argc, char *argv[])
0x00, 0x00, 0x01,
AVRCP_STATUS_INVALID_PARAM));
+ /* Player Application Settings tests */
+
+ define_test("/TP/PAS/BV-01-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+ 0x00, 0x19, 0x58, 0x11, 0x00, 0x00,
+ 0x00));
+
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 4/5] android/avrcp: Add list player attributes command
From: Andrei Emeltchenko @ 2014-02-27 9:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393492291-15099-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
android/avrcp-lib.c | 8 ++++++++
android/avrcp-lib.h | 2 ++
2 files changed, 10 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 6ae8df8..3db5bda 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -304,3 +304,11 @@ int avrcp_get_capabilities(struct avrcp *session, uint8_t param,
AVRCP_GET_CAPABILITIES, ¶m, sizeof(param),
func, user_data);
}
+
+int avrcp_list_player_attributes(struct avrcp *session, avctp_rsp_cb func,
+ void *user_data)
+{
+ return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
+ AVRCP_LIST_PLAYER_ATTRIBUTES, NULL, 0,
+ func, user_data);
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index e6e12c1..7283203 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -108,3 +108,5 @@ int avrcp_init_uinput(struct avrcp *session, const char *name,
int avrcp_get_capabilities(struct avrcp *session, uint8_t param,
avctp_rsp_cb func, void *user_data);
+int avrcp_list_player_attributes(struct avrcp *session, avctp_rsp_cb func,
+ void *user_data);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 3/5] unit/avrcp: Add /TP/CFG/BI-01-C test
From: Andrei Emeltchenko @ 2014-02-27 9:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393492291-15099-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies the get capabilities response issued from the Target when
an invalid capability is requested (0x7f).
---
unit/test-avrcp.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index a43985a..0924a7e 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -311,6 +311,8 @@ static uint8_t avrcp_handle_get_capabilities(struct avrcp *session,
{
uint32_t id = 0x001958;
+ DBG("params[0] %d params_len %d", params[0], *params_len);
+
if (*params_len != 1)
goto fail;
@@ -441,5 +443,14 @@ int main(int argc, char *argv[])
0x00, 0x19, 0x58, 0x10, 0x00, 0x00,
0x05, 0x02, 0x01, 0x00, 0x19, 0x58));
+ define_test("/TP/CFG/BI-01-C", test_server,
+ raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+ 0x00, 0x19, 0x58, 0x10, 0x00, 0x00,
+ 0x01, 0x7f),
+ raw_pdu(0x02, 0x11, 0x0e, AVC_CTYPE_REJECTED,
+ 0x48, 0x00, 0x00, 0x19, 0x58, 0x10,
+ 0x00, 0x00, 0x01,
+ AVRCP_STATUS_INVALID_PARAM));
+
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 2/5] unit/avrcp: Fix lengths byte order
From: Andrei Emeltchenko @ 2014-02-27 9:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393492291-15099-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
params_len is passed as function argument and needs to be in host byte
order.
---
unit/test-avrcp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index f222df8..a43985a 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -323,7 +323,7 @@ static uint8_t avrcp_handle_get_capabilities(struct avrcp *session,
}
fail:
- *params_len = htons(1);
+ *params_len = 1;
params[0] = AVRCP_STATUS_INVALID_PARAM;
return AVC_CTYPE_REJECTED;
--
1.8.3.2
^ permalink raw reply related
* [PATCH] doc: Update test coverage document
From: Andrei Emeltchenko @ 2014-02-27 9:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393492291-15099-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Update AVRCP test numbers.
---
doc/test-coverage.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index d37bcb8..79cace9 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -18,7 +18,7 @@ test-ringbuf 3 Ring buffer functionality
test-queue 1 Queue handling functionality
test-avdtp 60 AVDTP qualification test cases
test-avctp 9 AVCTP qualification test cases
-test-avrcp 7 AVRCP qualification test cases
+test-avrcp 13 AVRCP qualification test cases
test-gobex 31 Generic OBEX functionality
test-gobex-packet 9 OBEX packet handling
test-gobex-header 28 OBEX header handling
--
1.8.3.2
^ permalink raw reply related
* [PATCH 1/5] android/avrcp: Refactor get_caps() to allow parameter
From: Andrei Emeltchenko @ 2014-02-27 9:11 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Allow passing parameter specifying capability ID.
---
android/avrcp-lib.c | 6 ++----
android/avrcp-lib.h | 4 ++--
unit/test-avrcp.c | 3 ++-
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 1b5a294..6ae8df8 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -297,11 +297,9 @@ static int avrcp_send_req(struct avrcp *session, uint8_t code, uint8_t subunit,
session->tx_buf, len, func, user_data);
}
-int avrcp_get_capabilities(struct avrcp *session, avctp_rsp_cb func,
- void *user_data)
+int avrcp_get_capabilities(struct avrcp *session, uint8_t param,
+ avctp_rsp_cb func, void *user_data)
{
- uint8_t param = CAP_EVENTS_SUPPORTED;
-
return avrcp_send_req(session, AVC_CTYPE_STATUS, AVC_SUBUNIT_PANEL,
AVRCP_GET_CAPABILITIES, ¶m, sizeof(param),
func, user_data);
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 75802b9..e6e12c1 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -106,5 +106,5 @@ void avrcp_set_passthrough_handlers(struct avrcp *session,
int avrcp_init_uinput(struct avrcp *session, const char *name,
const char *address);
-int avrcp_get_capabilities(struct avrcp *session, avctp_rsp_cb func,
- void *user_data);
+int avrcp_get_capabilities(struct avrcp *session, uint8_t param,
+ avctp_rsp_cb func, void *user_data);
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index bcd8f88..f222df8 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -353,7 +353,8 @@ static void test_client(gconstpointer data)
struct context *context = create_context(0x0100, data);
if (g_str_equal(context->data->test_name, "/TP/CFG/BV-01-C"))
- avrcp_get_capabilities(context->session, NULL, NULL);
+ avrcp_get_capabilities(context->session, CAP_EVENTS_SUPPORTED,
+ NULL, NULL);
execute_context(context);
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH] doc: Update test coverage document
From: Andrei Emeltchenko @ 2014-02-27 7:57 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Update AVRCP test numbers.
---
doc/test-coverage.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index d37bcb8..79cace9 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -18,7 +18,7 @@ test-ringbuf 3 Ring buffer functionality
test-queue 1 Queue handling functionality
test-avdtp 60 AVDTP qualification test cases
test-avctp 9 AVCTP qualification test cases
-test-avrcp 7 AVRCP qualification test cases
+test-avrcp 13 AVRCP qualification test cases
test-gobex 31 Generic OBEX functionality
test-gobex-packet 9 OBEX packet handling
test-gobex-header 28 OBEX header handling
--
1.8.3.2
^ permalink raw reply related
* [PATCH 2/2] Bluetooth: Use RPAs for SMP when used in LE connection establishment
From: Marcel Holtmann @ 2014-02-27 5:54 UTC (permalink / raw)
To: linux-bluetooth
When a LE connection has been established using RPAs either for the
local or peer address, the SMP requires to the RPA and not the identity
address. The HCI connection structure might already resolved the RPA
into the identity address and identity address type. So if the RPA
is stored, then use it for SMP.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/smp.c | 94 +++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 77 insertions(+), 17 deletions(-)
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 0de98fe23330..13dee699c25b 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -437,22 +437,52 @@ static void confirm_work(struct work_struct *work)
struct hci_dev *hdev = conn->hcon->hdev;
struct crypto_blkcipher *tfm = hdev->tfm_aes;
struct smp_cmd_pairing_confirm cp;
- int ret;
+ bdaddr_t *init_addr, *resp_addr;
+ u8 init_addr_type, resp_addr_type;
u8 res[16], reason;
+ int ret;
BT_DBG("conn %p", conn);
/* Prevent mutual access to hdev->tfm_aes */
hci_dev_lock(hdev);
- if (conn->hcon->out)
- ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
- conn->hcon->src_type, &conn->hcon->src,
- conn->hcon->dst_type, &conn->hcon->dst, res);
- else
- ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
- conn->hcon->dst_type, &conn->hcon->dst,
- conn->hcon->src_type, &conn->hcon->src, res);
+ if (conn->hcon->out) {
+ if (bacmp(&conn->hcon->src_rpa, BDADDR_ANY)) {
+ init_addr = &conn->hcon->src_rpa;
+ init_addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ init_addr = &conn->hcon->src;
+ init_addr_type = conn->hcon->src_type;
+ }
+
+ if (bacmp(&conn->hcon->dst_rpa, BDADDR_ANY)) {
+ resp_addr = &conn->hcon->dst_rpa;
+ resp_addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ resp_addr = &conn->hcon->dst;
+ resp_addr_type = conn->hcon->dst_type;
+ }
+ } else {
+ if (bacmp(&conn->hcon->dst_rpa, BDADDR_ANY)) {
+ init_addr = &conn->hcon->dst_rpa;
+ init_addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ init_addr = &conn->hcon->dst;
+ init_addr_type = conn->hcon->dst_type;
+ }
+
+ if (bacmp(&conn->hcon->src_rpa, BDADDR_ANY)) {
+ resp_addr = &conn->hcon->src_rpa;
+ resp_addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ resp_addr = &conn->hcon->src;
+ resp_addr_type = conn->hcon->src_type;
+ }
+ }
+
+ ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
+ init_addr_type, init_addr, resp_addr_type, resp_addr, res);
hci_dev_unlock(hdev);
@@ -479,6 +509,8 @@ static void random_work(struct work_struct *work)
struct hci_conn *hcon = conn->hcon;
struct hci_dev *hdev = hcon->hdev;
struct crypto_blkcipher *tfm = hdev->tfm_aes;
+ bdaddr_t *init_addr, *resp_addr;
+ u8 init_addr_type, resp_addr_type;
u8 reason, confirm[16], res[16], key[16];
int ret;
@@ -492,14 +524,42 @@ static void random_work(struct work_struct *work)
/* Prevent mutual access to hdev->tfm_aes */
hci_dev_lock(hdev);
- if (hcon->out)
- ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
- hcon->src_type, &hcon->src,
- hcon->dst_type, &hcon->dst, res);
- else
- ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
- hcon->dst_type, &hcon->dst,
- hcon->src_type, &hcon->src, res);
+ if (conn->hcon->out) {
+ if (bacmp(&conn->hcon->src_rpa, BDADDR_ANY)) {
+ init_addr = &conn->hcon->src_rpa;
+ init_addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ init_addr = &conn->hcon->src;
+ init_addr_type = conn->hcon->src_type;
+ }
+
+ if (bacmp(&conn->hcon->dst_rpa, BDADDR_ANY)) {
+ resp_addr = &conn->hcon->dst_rpa;
+ resp_addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ resp_addr = &conn->hcon->dst;
+ resp_addr_type = conn->hcon->dst_type;
+ }
+ } else {
+ if (bacmp(&conn->hcon->dst_rpa, BDADDR_ANY)) {
+ init_addr = &conn->hcon->dst_rpa;
+ init_addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ init_addr = &conn->hcon->dst;
+ init_addr_type = conn->hcon->dst_type;
+ }
+
+ if (bacmp(&conn->hcon->src_rpa, BDADDR_ANY)) {
+ resp_addr = &conn->hcon->src_rpa;
+ resp_addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ resp_addr = &conn->hcon->src;
+ resp_addr_type = conn->hcon->src_type;
+ }
+ }
+
+ ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
+ init_addr_type, init_addr, resp_addr_type, resp_addr, res);
hci_dev_unlock(hdev);
--
1.8.5.3
^ permalink raw reply related
* [PATCH 1/2] Bluetooth: Store source and destination RPAs of a connection
From: Marcel Holtmann @ 2014-02-27 5:54 UTC (permalink / raw)
To: linux-bluetooth
When using resolvable private addresses (RPA) either for local or peer
devices, the RPA in use it needed for the SMP procedures. Either during
initial pairing or re-pairing for security level elevation.
It is important to store the actual used RPAs and not the current one
of the controller or peer. These might change over time, but for the
security procedures that RPA that the connection has been established
with are suppose to be used.
In case the local or peer device is not using RPAs, then the value
BDADDR_ANY will be stored to clearly identity that it is either a
public address, static random or unresolvable random address.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
include/net/bluetooth/hci_core.h | 2 ++
net/bluetooth/hci_conn.c | 7 +++++++
net/bluetooth/hci_event.c | 13 +++++++++++++
3 files changed, 22 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 79a75edc62d0..9326437f2295 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -328,8 +328,10 @@ struct hci_conn {
bdaddr_t dst;
__u8 dst_type;
+ bdaddr_t dst_rpa;
bdaddr_t src;
__u8 src_type;
+ bdaddr_t src_rpa;
__u16 handle;
__u16 state;
__u8 mode;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 7d6f05e3cae8..bf61b9f1af23 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -576,6 +576,13 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
*/
conn->src_type = own_addr_type;
+ /* Store the current local resolvable random address
+ * that will be used for connection establishment. It
+ * will be needed for pairing procedures.
+ */
+ if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
+ bacpy(&conn->src_rpa, &hdev->rpa);
+
cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
cp.scan_window = cpu_to_le16(hdev->le_scan_window);
bacpy(&cp.peer_addr, &conn->dst);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index cda92db2a9fc..03ebb10c453c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3634,6 +3634,14 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn->src_type = ADDR_LE_DEV_RANDOM;
}
+ /* Store the current local resolvable random address
+ * that has been used either in advertising or when
+ * triggering this connection establishment. It will
+ * be needed for pairing procedures.
+ */
+ if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
+ bacpy(&conn->src_rpa, &hdev->rpa);
+
if (ev->role == LE_CONN_ROLE_MASTER) {
conn->out = true;
conn->link_mode |= HCI_LM_MASTER;
@@ -3668,9 +3676,14 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
* address first. Now if it can be converted back into the
* identity address, start using the identity address from
* now on.
+ *
+ * The resolvable random address of the peer is first stored
+ * in dst_rpa since it might be needed for security level
+ * upgrade procedures later.
*/
irk = hci_get_irk(hdev, &conn->dst, conn->dst_type);
if (irk) {
+ bacpy(&conn->dst_rpa, &conn->dst);
bacpy(&conn->dst, &irk->bdaddr);
conn->dst_type = irk->addr_type;
}
--
1.8.5.3
^ permalink raw reply related
* Re: [PATCH v2 17/17] Bluetooth: Update background scan parameters
From: Marcel Holtmann @ 2014-02-27 3:44 UTC (permalink / raw)
To: Andre Guedes; +Cc: linux-bluetooth
In-Reply-To: <1393456916-22701-17-git-send-email-andre.guedes@openbossa.org>
Hi Andre,
> If new scanning parameters are set while background scan is running,
> we should restart background scanning so these parameters are updated.
>
> Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
> ---
> net/bluetooth/mgmt.c | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
all 17 patches have been applied to bluetooth-next tree.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] tty: Fix low_latency BUG
From: Feng Tang @ 2014-02-27 3:28 UTC (permalink / raw)
To: Peter Hurley
Cc: Greg Kroah-Hartman, Jiri Slaby, linux-serial, Beat Bolli,
Pavel Roskin, Linux Kernel Mailing List, Jiri Kosina,
David Sterba, Felipe Balbi, Grant Edwards, Stanislaw Gruszka,
Hal Murray, Alan Cox, stable, linux-bluetooth, feng.tang,
bin.yang, alek.du
In-Reply-To: <530E0AD3.7040909@hurleysoftware.com>
Hi Peter,
2014-02-26 23:40 GMT+08:00 Peter Hurley <peter@hurleysoftware.com>:
> [ +cc linux-bluetooth ]
>>>
>>> Historically, low_latency was used to force wake-up the reading
>>> process rather than wait for the next scheduler tick. The
>>> effect was to trim multiple milliseconds of latency from
>>> when the process would receive new data.
>>>
>>> Recent tests [1] have shown that the reading process now receives
>>> data with only 10's of microseconds latency without low_latency set.
>>
>>
>> The 10's of miscroseconds is ok for 115200 bps like device, but it may
>> hurt the high speed device like Bluetooth which runs at 3M/4M bps or
>> higher.
>
>
> The tests were run at 400Mbps, so 3Mbps or 4Mbps is not a problem
> (but I think you may be confusing throughput with latency).
I wrote the serial driver for intel mid platforms which are widely used
in current smart phones, so I guess I know what I'm talking :)
Our test and customer test cover both the performance and latency.
say like transferring 2 GB file while using BT A2DP to playing music.
Also I heard there is some app which will do real time void/data
exchange with paired bluetooth, here microseconds really means
something.
>
> FWIW, two things affected the latency times of those particular tests;
> 1) the kernel firewire subsystem handles rx data in a tasklet (so not
> directly from IRQ) which negatively affected the latency reported, and
> 2) the ftrace instrumentation is not free and there are several traces per
> rx.
>
> If you look carefully at the test trace data, you'll see that the timestamps
> from tty_flip_buffer_push() of the rx data to n_tty_write() of the
> response averages _~11us_; this is the measured latency from tty driver
> receiving the rx data to reading of that data *and* the process
> response (which comes back up through several tty locks).
>
> Naturally, in mainline kernel, the scheduler load will affect the
> measured latency *but that's true regardless of low_latency rx steering
> because the user-space process must still be woken to complete the read*.
>
>
>> More and more smartphones are using uart as the Bluetooth data
>> interface due to its low-pin, low-power feature, and many of them
>> are using HZ=100 kernel, I'm afraid this added delay may cause
>> some problem.
>
>
> Some hard data showing a real problem would help further this
> discussion; my belief is that 3.12+ w/o low_latency rx steering
> will outperform 3.11- w/ low_latency rx steering in every test.
As for measurements, I guess it should cover 2 parts:
1. the performance, like the BT file transfer data rate
2. the latency, like the real time BT communication
I'll try to get some test data soon. Also I'm wondering what devices
have you tested? regarding these 2 points.
>
> I'm glad to hear that the Bluetooth uart interface is getting
> some use; that means someone will soon be fixing the hard lockup
> in hci_uart_tx_wakeup() reported here:
I'm not very familiar with the BT devices on our platforms, but most
of them are not using the in-kernel BT driver, some just use the
n_tty ldisc and the raw data, some use their own ldisc driver.
Thanks,
Feng
^ permalink raw reply
* [PATCH v2 17/17] Bluetooth: Update background scan parameters
From: Andre Guedes @ 2014-02-26 23:21 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393456916-22701-1-git-send-email-andre.guedes@openbossa.org>
If new scanning parameters are set while background scan is running,
we should restart background scanning so these parameters are updated.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
net/bluetooth/mgmt.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 2e6564e..4c4912e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3924,6 +3924,21 @@ static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
+ /* If background scan is running, restart it so new parameters are
+ * loaded.
+ */
+ if (test_bit(HCI_LE_SCAN, &hdev->dev_flags) &&
+ hdev->discovery.state == DISCOVERY_STOPPED) {
+ struct hci_request req;
+
+ hci_req_init(&req, hdev);
+
+ hci_req_add_le_scan_disable(&req);
+ hci_req_add_le_passive_scan(&req);
+
+ hci_req_run(&req, NULL);
+ }
+
hci_dev_unlock(hdev);
return err;
--
1.8.5.4
^ permalink raw reply related
* [PATCH v2 16/17] Bluetooth: Create hci_req_add_le_passive_scan helper
From: Andre Guedes @ 2014-02-26 23:21 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393456916-22701-1-git-send-email-andre.guedes@openbossa.org>
This patches creates the public hci_req_add_le_passive_scan helper so
it can be re-used outside hci_core.c in the next patch.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_core.c | 56 ++++++++++++++++++++++------------------
2 files changed, 32 insertions(+), 25 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4b192d0..79a75ed 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1150,6 +1150,7 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
void hci_req_add_le_scan_disable(struct hci_request *req);
+void hci_req_add_le_passive_scan(struct hci_request *req);
struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u32 timeout);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0b96f20..bbd085d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -5115,6 +5115,36 @@ void hci_req_add_le_scan_disable(struct hci_request *req)
hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
}
+void hci_req_add_le_passive_scan(struct hci_request *req)
+{
+ struct hci_cp_le_set_scan_param param_cp;
+ struct hci_cp_le_set_scan_enable enable_cp;
+ struct hci_dev *hdev = req->hdev;
+ u8 own_addr_type;
+
+ /* Set require_privacy to true to avoid identification from
+ * unknown peer devices. Since this is passive scanning, no
+ * SCAN_REQ using the local identity should be sent. Mandating
+ * privacy is just an extra precaution.
+ */
+ if (hci_update_random_address(req, true, &own_addr_type))
+ return;
+
+ memset(¶m_cp, 0, sizeof(param_cp));
+ param_cp.type = LE_SCAN_PASSIVE;
+ param_cp.interval = cpu_to_le16(hdev->le_scan_interval);
+ param_cp.window = cpu_to_le16(hdev->le_scan_window);
+ param_cp.own_address_type = own_addr_type;
+ hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
+ ¶m_cp);
+
+ memset(&enable_cp, 0, sizeof(enable_cp));
+ enable_cp.enable = LE_SCAN_ENABLE;
+ enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+ hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+ &enable_cp);
+}
+
static void update_background_scan_complete(struct hci_dev *hdev, u8 status)
{
if (status)
@@ -5130,8 +5160,6 @@ static void update_background_scan_complete(struct hci_dev *hdev, u8 status)
*/
void hci_update_background_scan(struct hci_dev *hdev)
{
- struct hci_cp_le_set_scan_param param_cp;
- struct hci_cp_le_set_scan_enable enable_cp;
struct hci_request req;
struct hci_conn *conn;
int err;
@@ -5151,8 +5179,6 @@ void hci_update_background_scan(struct hci_dev *hdev)
BT_DBG("%s stopping background scanning", hdev->name);
} else {
- u8 own_addr_type;
-
/* If there is at least one pending LE connection, we should
* keep the background scan running.
*/
@@ -5169,27 +5195,7 @@ void hci_update_background_scan(struct hci_dev *hdev)
if (conn)
return;
- /* Set require_privacy to true to avoid identification from
- * unknown peer devices. Since this is passive scanning, no
- * SCAN_REQ using the local identity should be sent. Mandating
- * privacy is just an extra precaution.
- */
- if (hci_update_random_address(&req, true, &own_addr_type))
- return;
-
- memset(¶m_cp, 0, sizeof(param_cp));
- param_cp.type = LE_SCAN_PASSIVE;
- param_cp.interval = cpu_to_le16(hdev->le_scan_interval);
- param_cp.window = cpu_to_le16(hdev->le_scan_window);
- param_cp.own_address_type = own_addr_type;
- hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
- ¶m_cp);
-
- memset(&enable_cp, 0, sizeof(enable_cp));
- enable_cp.enable = LE_SCAN_ENABLE;
- enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
- hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
- &enable_cp);
+ hci_req_add_le_passive_scan(&req);
BT_DBG("%s starting background scanning", hdev->name);
}
--
1.8.5.4
^ permalink raw reply related
* [PATCH v2 15/17] Bluetooth: Add le_auto_conn file on debugfs
From: Andre Guedes @ 2014-02-26 23:21 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393456916-22701-1-git-send-email-andre.guedes@openbossa.org>
This patch adds to debugfs the le_auto_conn file. This file will be
used to test LE auto connection infrastructure.
This file accept writes in the following format:
"add <address> <address_type> [auto_connect]"
"del <address> <address_type>"
"clr"
The <address type> values are:
* 0 for public address
* 1 for random address
The [auto_connect] values are (for more details see struct hci_
conn_params):
* 0 for disabled (default)
* 1 for always
* 2 for link loss
So for instance, if you want the kernel autonomously establishes
connections with device AA:BB:CC:DD:EE:FF (public address) every
time the device enters in connectable mode (starts advertising),
you should run the command:
$ echo "add AA:BB:CC:DD:EE:FF 0 1" > /sys/kernel/debug/bluetooth/hci0/le_auto_conn
To delete the connection parameters for that device, run the command:
$ echo "del AA:BB:CC:DD:EE:FF 0" > /sys/kernel/debug/bluetooth/hci0/le_auto_conn
To clear the connection parameters list, run the command:
$ echo "clr" > /sys/kernel/debug/bluetooth/hci0/le_auto_conn
Finally. to get the list of connection parameters configured in kernel,
read the le_auto_conn file:
$ cat /sys/kernel/debug/bluetooth/hci0/le_auto_conn
This file is created only if LE is enabled.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
net/bluetooth/hci_core.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 6d83ca0..0b96f20 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -896,6 +896,115 @@ static const struct file_operations lowpan_debugfs_fops = {
.llseek = default_llseek,
};
+static int le_auto_conn_show(struct seq_file *sf, void *ptr)
+{
+ struct hci_dev *hdev = sf->private;
+ struct hci_conn_params *p;
+
+ hci_dev_lock(hdev);
+
+ list_for_each_entry(p, &hdev->le_conn_params, list) {
+ seq_printf(sf, "%pMR %u %u\n", &p->addr, p->addr_type,
+ p->auto_connect);
+ }
+
+ hci_dev_unlock(hdev);
+
+ return 0;
+}
+
+static int le_auto_conn_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, le_auto_conn_show, inode->i_private);
+}
+
+static ssize_t le_auto_conn_write(struct file *file, const char __user *data,
+ size_t count, loff_t *offset)
+{
+ struct seq_file *sf = file->private_data;
+ struct hci_dev *hdev = sf->private;
+ u8 auto_connect = 0;
+ bdaddr_t addr;
+ u8 addr_type;
+ char *buf;
+ int err = 0;
+ int n;
+
+ /* Don't allow partial write */
+ if (*offset != 0)
+ return -EINVAL;
+
+ if (count < 3)
+ return -EINVAL;
+
+ buf = kzalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, data, count)) {
+ err = -EFAULT;
+ goto done;
+ }
+
+ if (memcmp(buf, "add", 3) == 0) {
+ n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu %hhu",
+ &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2],
+ &addr.b[1], &addr.b[0], &addr_type,
+ &auto_connect);
+
+ if (n < 7) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ hci_dev_lock(hdev);
+ err = hci_conn_params_add(hdev, &addr, addr_type, auto_connect,
+ hdev->le_conn_min_interval,
+ hdev->le_conn_max_interval);
+ hci_dev_unlock(hdev);
+
+ if (err)
+ goto done;
+ } else if (memcmp(buf, "del", 3) == 0) {
+ n = sscanf(&buf[4], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu",
+ &addr.b[5], &addr.b[4], &addr.b[3], &addr.b[2],
+ &addr.b[1], &addr.b[0], &addr_type);
+
+ if (n < 7) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ hci_dev_lock(hdev);
+ hci_conn_params_del(hdev, &addr, addr_type);
+ hci_dev_unlock(hdev);
+ } else if (memcmp(buf, "clr", 3) == 0) {
+ hci_dev_lock(hdev);
+ hci_conn_params_clear(hdev);
+ hci_pend_le_conns_clear(hdev);
+ hci_update_background_scan(hdev);
+ hci_dev_unlock(hdev);
+ } else {
+ err = -EINVAL;
+ }
+
+done:
+ kfree(buf);
+
+ if (err)
+ return err;
+ else
+ return count;
+}
+
+static const struct file_operations le_auto_conn_fops = {
+ .open = le_auto_conn_open,
+ .read = seq_read,
+ .write = le_auto_conn_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/* ---- HCI requests ---- */
static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
@@ -1694,6 +1803,8 @@ static int __hci_init(struct hci_dev *hdev)
hdev, &adv_channel_map_fops);
debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev,
&lowpan_debugfs_fops);
+ debugfs_create_file("le_auto_conn", 0644, hdev->debugfs, hdev,
+ &le_auto_conn_fops);
}
return 0;
--
1.8.5.4
^ permalink raw reply related
* [PATCH v2 14/17] Bluetooth: Support resolvable private addresses
From: Andre Guedes @ 2014-02-26 23:21 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393456916-22701-1-git-send-email-andre.guedes@openbossa.org>
Only identity addresses are inserted into hdev->pend_le_conns. So,
in order to support resolvable private addresses in auto connection
mechanism, we should resolve the address before checking for pending
connections.
Thus, this patch adds an extra check in check_pending_le_conn() and
updates 'addr' and 'addr_type' variables before hci_pend_le_conn_
lookup().
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
net/bluetooth/hci_event.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 46da8b6..cda92db 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3706,6 +3706,16 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
u8 addr_type)
{
struct hci_conn *conn;
+ struct smp_irk *irk;
+
+ /* If this is a resolvable address, we should resolve it and then
+ * update address and address type variables.
+ */
+ irk = hci_get_irk(hdev, addr, addr_type);
+ if (irk) {
+ addr = &irk->bdaddr;
+ addr_type = irk->addr_type;
+ }
if (!hci_pend_le_conn_lookup(hdev, addr, addr_type))
return;
--
1.8.5.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox