* Re: [PATCH] compat: fix system crash on 2.6.35 when flushing work
From: Zefir Kurtisi @ 2012-08-13 11:15 UTC (permalink / raw)
To: C. McPherson; +Cc: mcgrof, lf_driver_backport, linux-wireless, linux-bluetooth
In-Reply-To: <5027D79E.9050607@verizon.net>
On 08/12/2012 06:19 PM, C. McPherson wrote:
> Zefir:
> Thanks a lot for this reference. All my systems are running Ubuntu
> 10.04/10.10. I was updating our compat-wireless with the stable
> compat-wireless 3.5
> and came across this crash in our testing lab. I added your patch and
> the stable compat-wireless 3.5 is now working with our Ubuntu.
>
> -Tex
>
>
Hi Tex,
the fix Hauke provided is the correct one. The QH I posted was a lucky
punch that for some reason prevented the system crashing without
resolving the issue.
^ permalink raw reply
* [RFC v4 8/8] Update test/test-oob to match new DBus OOB API
From: Szymon Janc @ 2012-08-13 10:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1344854800-20972-1-git-send-email-szymon.janc@tieto.com>
---
test/test-oob | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/test-oob b/test/test-oob
index bec9de5..d44215f 100755
--- a/test/test-oob
+++ b/test/test-oob
@@ -68,8 +68,8 @@ if __name__ == '__main__':
print()
print("Exchanging Out of Band data...")
- oob_adapter0.AddRemoteData(adapter1_address, oob1[0], oob1[1])
- oob_adapter1.AddRemoteData(adapter0_address, oob0[0], oob0[1])
+ oob_adapter0.AddRemoteData(adapter1_address, oob1)
+ oob_adapter1.AddRemoteData(adapter0_address, oob0)
print("Done.")
print()
--
1.7.9.5
^ permalink raw reply related
* [RFC v4 7/8] dbusoob: Reply with error if SSP is not supported
From: Szymon Janc @ 2012-08-13 10:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1344854800-20972-1-git-send-email-szymon.janc@tieto.com>
Reply with org.bluez.Error.NotSupported if methods were called on
adapter without SSP enabled.
---
plugins/dbusoob.c | 9 +++++++++
src/adapter.c | 5 +++++
src/adapter.h | 2 ++
src/mgmt.c | 7 +++++++
src/mgmt.h | 2 ++
5 files changed, 25 insertions(+)
diff --git a/plugins/dbusoob.c b/plugins/dbusoob.c
index 0e0eeca..885f247 100644
--- a/plugins/dbusoob.c
+++ b/plugins/dbusoob.c
@@ -137,6 +137,9 @@ static DBusMessage *read_local_data(DBusConnection *conn, DBusMessage *msg,
struct btd_adapter *adapter = data;
struct oob_request *oob_request;
+ if (!btd_adapter_ssp_enabled(adapter))
+ return btd_error_not_supported(msg);
+
if (find_oob_request(adapter))
return btd_error_in_progress(msg);
@@ -258,6 +261,9 @@ static DBusMessage *add_remote_data(DBusConnection *conn, DBusMessage *msg,
struct oob_data remote_data;
struct btd_device *device;
+ if (!btd_adapter_ssp_enabled(adapter))
+ return btd_error_not_supported(msg);
+
memset(&remote_data, 0, sizeof(remote_data));
dbus_message_iter_init(msg, &args);
@@ -290,6 +296,9 @@ static DBusMessage *remove_remote_data(DBusConnection *conn, DBusMessage *msg,
const char *addr;
bdaddr_t bdaddr;
+ if (!btd_adapter_ssp_enabled(adapter))
+ return btd_error_not_supported(msg);
+
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
diff --git a/src/adapter.c b/src/adapter.c
index b7691d0..e6b5559 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3498,3 +3498,8 @@ int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
{
return mgmt_remove_remote_oob_data(adapter->dev_id, bdaddr);
}
+
+int btd_adapter_ssp_enabled(struct btd_adapter *adapter)
+{
+ return mgmt_ssp_enabled(adapter->dev_id);
+}
diff --git a/src/adapter.h b/src/adapter.h
index d8a1bb1..5a0247e 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -230,3 +230,5 @@ int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
int btd_adapter_gatt_server_start(struct btd_adapter *adapter);
void btd_adapter_gatt_server_stop(struct btd_adapter *adapter);
+
+int btd_adapter_ssp_enabled(struct btd_adapter *adapter);
diff --git a/src/mgmt.c b/src/mgmt.c
index c893972..b3ae776 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -2474,3 +2474,10 @@ int mgmt_load_ltks(int index, GSList *keys)
return err;
}
+
+int mgmt_ssp_enabled(int index)
+{
+ struct controller_info *info = &controllers[index];
+
+ return mgmt_ssp(info->current_settings);
+}
diff --git a/src/mgmt.h b/src/mgmt.h
index 0658198..95245d2 100644
--- a/src/mgmt.h
+++ b/src/mgmt.h
@@ -78,3 +78,5 @@ int mgmt_remove_remote_oob_data(int index, bdaddr_t *bdaddr);
int mgmt_confirm_name(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
gboolean name_known);
+
+int mgmt_ssp_enabled(int index);
--
1.7.9.5
^ permalink raw reply related
* [RFC v4 6/8] dbusoob: Add support for Name in AddRemoteData
From: Szymon Janc @ 2012-08-13 10:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1344854800-20972-1-git-send-email-szymon.janc@tieto.com>
Name received in AddRemoteData is stored for future use when device
object is created.
---
plugins/dbusoob.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/plugins/dbusoob.c b/plugins/dbusoob.c
index 97de9c0..0e0eeca 100644
--- a/plugins/dbusoob.c
+++ b/plugins/dbusoob.c
@@ -57,6 +57,7 @@ struct oob_data {
uint8_t *hash;
uint8_t *randomizer;
uint32_t class;
+ char *name;
};
static GSList *oob_requests = NULL;
@@ -197,6 +198,12 @@ static gboolean parse_data(DBusMessageIter *data, struct oob_data *remote_data)
dbus_message_iter_get_basic(&value,
&remote_data->class);
+ } else if (strcasecmp(key, "Name") == 0) {
+ if (var != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value,
+ &remote_data->name);
}
dbus_message_iter_next(data);
@@ -215,8 +222,10 @@ static gboolean parse_data(DBusMessageIter *data, struct oob_data *remote_data)
static gboolean store_data(struct btd_adapter *adapter, struct oob_data *data)
{
bdaddr_t bdaddr;
+ bdaddr_t local;
str2ba(data->addr, &bdaddr);
+ adapter_get_address(adapter, &local);
if (data->hash) {
uint8_t empty_randomizer[16];
@@ -231,12 +240,11 @@ static gboolean store_data(struct btd_adapter *adapter, struct oob_data *data)
return FALSE;
}
- if (data->class) {
- bdaddr_t local;
- adapter_get_address(adapter, &local);
-
+ if (data->class)
write_remote_class(&local, &bdaddr, data->class);
- }
+
+ if (data->name)
+ write_device_name(&local, &bdaddr, 0, data->name);
return TRUE;
}
--
1.7.9.5
^ permalink raw reply related
* [RFC v4 5/8] dbusoob: Add support for Class in AddRemoteData
From: Szymon Janc @ 2012-08-13 10:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1344854800-20972-1-git-send-email-szymon.janc@tieto.com>
Class received in AddRemoteData is stored for future use when device
object is created.
---
plugins/dbusoob.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/plugins/dbusoob.c b/plugins/dbusoob.c
index 2ae80fa..97de9c0 100644
--- a/plugins/dbusoob.c
+++ b/plugins/dbusoob.c
@@ -43,6 +43,7 @@
#include "event.h"
#include "error.h"
#include "oob.h"
+#include "storage.h"
#define OOB_INTERFACE "org.bluez.OutOfBand"
@@ -55,6 +56,7 @@ struct oob_data {
char *addr;
uint8_t *hash;
uint8_t *randomizer;
+ uint32_t class;
};
static GSList *oob_requests = NULL;
@@ -189,6 +191,12 @@ static gboolean parse_data(DBusMessageIter *data, struct oob_data *remote_data)
if (size != 16)
return FALSE;
+ } else if (strcasecmp(key, "Class") == 0) {
+ if (var != DBUS_TYPE_UINT32)
+ return FALSE;
+
+ dbus_message_iter_get_basic(&value,
+ &remote_data->class);
}
dbus_message_iter_next(data);
@@ -223,6 +231,13 @@ static gboolean store_data(struct btd_adapter *adapter, struct oob_data *data)
return FALSE;
}
+ if (data->class) {
+ bdaddr_t local;
+ adapter_get_address(adapter, &local);
+
+ write_remote_class(&local, &bdaddr, data->class);
+ }
+
return TRUE;
}
--
1.7.9.5
^ permalink raw reply related
* [RFC v4 4/8] dbusoob: Change AddRemoteData to match new API
From: Szymon Janc @ 2012-08-13 10:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1344854800-20972-1-git-send-email-szymon.janc@tieto.com>
AddRemoteData now expect dictionary for data instead of hardcoded pair
of arrays.
---
plugins/dbusoob.c | 126 +++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 108 insertions(+), 18 deletions(-)
diff --git a/plugins/dbusoob.c b/plugins/dbusoob.c
index 92c4df1..2ae80fa 100644
--- a/plugins/dbusoob.c
+++ b/plugins/dbusoob.c
@@ -51,6 +51,12 @@ struct oob_request {
DBusMessage *msg;
};
+struct oob_data {
+ char *addr;
+ uint8_t *hash;
+ uint8_t *randomizer;
+};
+
static GSList *oob_requests = NULL;
static DBusConnection *connection = NULL;
@@ -142,28 +148,113 @@ static DBusMessage *read_local_data(DBusConnection *conn, DBusMessage *msg,
return NULL;
}
-static DBusMessage *add_remote_data(DBusConnection *conn, DBusMessage *msg,
- void *data)
+static gboolean parse_data(DBusMessageIter *data, struct oob_data *remote_data)
+{
+ while (dbus_message_iter_get_arg_type(data) == DBUS_TYPE_DICT_ENTRY) {
+ const char *key;
+ DBusMessageIter value, entry;
+ int var;
+
+ dbus_message_iter_recurse(data, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ var = dbus_message_iter_get_arg_type(&value);
+ if (strcasecmp(key, "Hash") == 0) {
+ DBusMessageIter array;
+ int size;
+
+ if (var != DBUS_TYPE_ARRAY)
+ return FALSE;
+
+ dbus_message_iter_recurse(&value, &array);
+ dbus_message_iter_get_fixed_array(&array,
+ &remote_data->hash, &size);
+
+ if (size != 16)
+ return FALSE;
+ } else if (strcasecmp(key, "Randomizer") == 0) {
+ DBusMessageIter array;
+ int size;
+
+ if (var != DBUS_TYPE_ARRAY)
+ return FALSE;
+
+ dbus_message_iter_recurse(&value, &array);
+ dbus_message_iter_get_fixed_array(&array,
+ &remote_data->randomizer,
+ &size);
+
+ if (size != 16)
+ return FALSE;
+ }
+
+ dbus_message_iter_next(data);
+ }
+
+ if (dbus_message_iter_get_arg_type(data) != DBUS_TYPE_INVALID)
+ return FALSE;
+
+ /* If randomizer is provided, hash also needs to be provided. */
+ if (remote_data->randomizer && !remote_data->hash)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean store_data(struct btd_adapter *adapter, struct oob_data *data)
{
- struct btd_adapter *adapter = data;
- uint8_t *hash, *randomizer;
- int32_t hlen, rlen;
- const char *addr;
bdaddr_t bdaddr;
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &addr,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hlen,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &rlen,
- DBUS_TYPE_INVALID))
- return btd_error_invalid_args(msg);
+ str2ba(data->addr, &bdaddr);
+
+ if (data->hash) {
+ uint8_t empty_randomizer[16];
- if (hlen != 16 || rlen != 16 || bachk(addr))
+ if (!data->randomizer) {
+ memset(empty_randomizer, 0, sizeof(empty_randomizer));
+ data->randomizer = empty_randomizer;
+ }
+
+ if (btd_adapter_add_remote_oob_data(adapter, &bdaddr,
+ data->hash, data->randomizer) < 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static DBusMessage *add_remote_data(DBusConnection *conn, DBusMessage *msg,
+ void *user_data)
+{
+ struct btd_adapter *adapter = user_data;
+ DBusMessageIter args;
+ DBusMessageIter data;
+ struct oob_data remote_data;
+ struct btd_device *device;
+
+ memset(&remote_data, 0, sizeof(remote_data));
+
+ dbus_message_iter_init(msg, &args);
+
+ dbus_message_iter_get_basic(&args, &remote_data.addr);
+ dbus_message_iter_next(&args);
+
+ if (bachk(remote_data.addr) < 0)
return btd_error_invalid_args(msg);
- str2ba(addr, &bdaddr);
+ device = adapter_find_device(adapter, remote_data.addr);
+ if (device && device_is_paired(device))
+ return btd_error_already_exists(msg);
+
+ dbus_message_iter_recurse(&args, &data);
+
+ if (!parse_data(&data, &remote_data))
+ return btd_error_invalid_args(msg);
- if (btd_adapter_add_remote_oob_data(adapter, &bdaddr, hash, randomizer))
+ if (!store_data(adapter, &remote_data))
return btd_error_failed(msg, "Request failed");
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
@@ -191,9 +282,8 @@ static DBusMessage *remove_remote_data(DBusConnection *conn, DBusMessage *msg,
static const GDBusMethodTable oob_methods[] = {
{ GDBUS_METHOD("AddRemoteData",
- GDBUS_ARGS({ "address", "s" }, { "hash", "ay" },
- { "randomizer", "ay" }), NULL,
- add_remote_data) },
+ GDBUS_ARGS({ "address", "s" }, { "data", "a{sv}"}),
+ NULL, add_remote_data) },
{ GDBUS_METHOD("RemoveRemoteData",
GDBUS_ARGS({ "address", "s" }), NULL,
remove_remote_data) },
--
1.7.9.5
^ permalink raw reply related
* [RFC v4 3/8] dbusoob: Change ReadLocalData to match new API
From: Szymon Janc @ 2012-08-13 10:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1344854800-20972-1-git-send-email-szymon.janc@tieto.com>
ReadLocalData now returns dictionary instead of hardcoded pair of
arrays.
---
plugins/dbusoob.c | 31 +++++++++++++++++++++++--------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/plugins/dbusoob.c b/plugins/dbusoob.c
index d259159..92c4df1 100644
--- a/plugins/dbusoob.c
+++ b/plugins/dbusoob.c
@@ -79,20 +79,36 @@ static void read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
{
struct DBusMessage *reply;
struct oob_request *oob_request;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
oob_request = find_oob_request(adapter);
if (!oob_request)
return;
- if (hash && randomizer)
- reply = g_dbus_create_reply(oob_request->msg,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, 16,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, 16,
- DBUS_TYPE_INVALID);
- else
+ if (!hash || !randomizer) {
reply = btd_error_failed(oob_request->msg,
"Failed to read local OOB data.");
+ goto done;
+ }
+
+ reply = dbus_message_new_method_return(oob_request->msg);
+ if (!reply)
+ goto done;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dict_append_array(&dict, "Hash", DBUS_TYPE_BYTE, &hash, 16);
+ dict_append_array(&dict, "Randomizer", DBUS_TYPE_BYTE, &randomizer, 16);
+
+ dbus_message_iter_close_container(&iter, &dict);
+done:
oob_requests = g_slist_remove(oob_requests, oob_request);
dbus_message_unref(oob_request->msg);
g_free(oob_request);
@@ -182,8 +198,7 @@ static const GDBusMethodTable oob_methods[] = {
GDBUS_ARGS({ "address", "s" }), NULL,
remove_remote_data) },
{ GDBUS_ASYNC_METHOD("ReadLocalData",
- NULL, GDBUS_ARGS({ "hash", "ay" },
- { "randomizer", "ay" }),
+ NULL, GDBUS_ARGS({ "data", "a{sv}" }),
read_local_data) },
{ }
};
--
1.7.9.5
^ permalink raw reply related
* [RFC v4 2/8] dbusoob: Simplify remove_remote_data
From: Szymon Janc @ 2012-08-13 10:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1344854800-20972-1-git-send-email-szymon.janc@tieto.com>
str2ba already checks if address is valid before converting and returns
-1 in case of failure.
---
plugins/dbusoob.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/plugins/dbusoob.c b/plugins/dbusoob.c
index 1791342..d259159 100644
--- a/plugins/dbusoob.c
+++ b/plugins/dbusoob.c
@@ -164,11 +164,9 @@ static DBusMessage *remove_remote_data(DBusConnection *conn, DBusMessage *msg,
DBUS_TYPE_INVALID))
return btd_error_invalid_args(msg);
- if (bachk(addr))
+ if (str2ba(addr, &bdaddr) < 0)
return btd_error_invalid_args(msg);
- str2ba(addr, &bdaddr);
-
if (btd_adapter_remove_remote_oob_data(adapter, &bdaddr))
return btd_error_failed(msg, "Request failed");
--
1.7.9.5
^ permalink raw reply related
* [RFC v4 1/8] dbusoob: Update API
From: Szymon Janc @ 2012-08-13 10:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1344854800-20972-1-git-send-email-szymon.janc@tieto.com>
Update DBus API so that it better matches inquiry result. It can now
also be used only for OOB discovery (hash and randomizer are optional).
Converting to dictionaries make it also easily extendible e.g. to add
support for BLE when proper whitepaper becomes available.
---
doc/oob-api.txt | 59 +++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 53 insertions(+), 6 deletions(-)
diff --git a/doc/oob-api.txt b/doc/oob-api.txt
index d838712..c3978fc 100644
--- a/doc/oob-api.txt
+++ b/doc/oob-api.txt
@@ -2,31 +2,77 @@ BlueZ D-Bus Out Of Band Pairing API description
===============================================
Copyright (C) 2011 Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
+Copyright (C) 2012 Tieto Poland
+
+Currently only Secure Simple Pairing is supported. This might change when white
+paper describing OOB pairing for Bluetooth Low Energy will become available.
+
+Out Of Band hierarchy
+=====================
Service org.bluez
Interface org.bluez.OutOfBand
Object path [variable prefix]/{hci0,hci1,...}
-Methods array{byte} hash, array{byte} randomizer ReadLocalData()
+Methods dict ReadLocalData()
This method reads local OOB data from adapter. Return
- value is pair of arrays 16 bytes each.
+ value is a dictionary. Following keys are possible:
+
+ array{byte} Hash:
+
+ 16 bytes hash blob.
+
+ array{byte} Randomizer:
- Note: This method will generate and return new local
- OOB data.
+ 16 bytes randomizer blob.
+
+ Other data that can be transmitted via OOB mechanism
+ can be obtained from org.bluez.Adapter interface.
+
+ Note: This method will generate and return new data
+ every time it is called. Data received in previous
+ calls is invalidated and cannot be used for pairing.
Possible errors: org.bluez.Error.Failed
org.bluez.Error.InProgress
+ org.bluez.Error.NotSupported
- void AddRemoteData(string address, array{byte} hash,
- array{byte} randomizer)
+ void AddRemoteData(string address, dict data)
This method adds new Out Of Band data for
specified address. If data for specified address
already exists it will be overwritten with new one.
+ All data is optional.
+
+ possible keys:
+
+ array{byte} Hash:
+
+ 16 bytes hash blob, it is used as is
+ so the size and byte order must match.
+
+ array{byte} Randomizer:
+
+ 16 bytes randomizer blob, it is used as
+ is so the size and byte order must
+ match. If Randomizer is provided Hash
+ also needs to be provided.
+
+ uint32 Class:
+
+ The Bluetooth class of device of the
+ remote device.
+
+ string Name:
+
+ Remote device name.
+
Possible errors: org.bluez.Error.Failed
org.bluez.Error.InvalidArguments
+ org.bluez.Error.AlreadyExists
+ org.bluez.Error.NotSupported
void RemoveRemoteData(string address)
@@ -36,3 +82,4 @@ Methods array{byte} hash, array{byte} randomizer ReadLocalData()
Possible errors: org.bluez.Error.Failed
org.bluez.Error.InvalidArguments
+ org.bluez.Error.NotSupported
--
1.7.9.5
^ permalink raw reply related
* [RFC v4 0/8] DBus OutOfBand API update
From: Szymon Janc @ 2012-08-13 10:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
Hi,
changes since V3:
- remove of DeviceFound signal (rationale below)
- remove of UUIDs from AddRemoteData dictionary
- AlreadyPaired -> AlreadyExist error change
- proposed implementation
After some more thinking about OOB API I've decided that emitting
DeviceFound signal when OOB data are provided is not the best thing to do.
Typical usecase with dbusoob plugin is to provide oob data and either start
pairing with CreatePairedDevice or wait for incoming pairing request. No need
to emit DeviceFound as OOB provider is already aware of device address and can
start pairing. If it doesn't provide pairing agent for device there will be
fallback to adapter agent (which doesn't need to know anything about OOB
channel).
For UUIDs removal is similar - OOB provider already knows which UUIDs are
supported by remote device and based on that can choose to pair or not. No
need to provide that to bluetoothd as it would be only used in DeviceFound
signal anyway.
Comments are welcome.
--
BR
Szymon Janc
Szymon Janc (8):
dbusoob: Update API
dbusoob: Simplify remove_remote_data
dbusoob: Change ReadLocalData to match new API
dbusoob: Change AddRemoteData to match new API
dbusoob: Add support for Class in AddRemoteData
dbusoob: Add support for Name in AddRemoteData
dbusoob: Reply with error if SSP is not supported
Update test/test-oob to match new DBus OOB API
doc/oob-api.txt | 59 ++++++++++++++--
plugins/dbusoob.c | 193 +++++++++++++++++++++++++++++++++++++++++++++--------
src/adapter.c | 5 ++
src/adapter.h | 2 +
src/mgmt.c | 7 ++
src/mgmt.h | 2 +
test/test-oob | 4 +-
7 files changed, 235 insertions(+), 37 deletions(-)
--
1.7.9.5
^ permalink raw reply
* Re: [PATCH] input: Fix crash when connecting HID keyboard
From: Johan Hedberg @ 2012-08-13 10:29 UTC (permalink / raw)
To: Andrzej Kaczmarek; +Cc: linux-bluetooth
In-Reply-To: <1343738904-12556-1-git-send-email-andrzej.kaczmarek@tieto.com>
Hi Andrzej,
On Tue, Jul 31, 2012, Andrzej Kaczmarek wrote:
> hidp_add_connection should return after setting up security watch when
> connecting HID keyboard, otherwise req will be freed and encrypt_notify
> callback will receive invalid pointer.
> ---
> profiles/input/device.c | 2 ++
> 1 file changed, 2 insertions(+)
Applied. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH BlueZ] btmgmt: Fix endianness conversion
From: Johan Hedberg @ 2012-08-13 10:27 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <1343743081-25474-1-git-send-email-anderson.lizardo@openbossa.org>
Hi Lizardo,
On Tue, Jul 31, 2012, Anderson Lizardo wrote:
> Flags field has 32-bit size. Same issue was fixed for mgmtops in
> 1801a4d45d74c29cebacaab79a07e9961300be41.
> ---
> tools/btmgmt.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Applied. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH v3 BlueZ] monitor: Fix endianness conversion
From: Johan Hedberg @ 2012-08-13 10:24 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <1343740877-16611-1-git-send-email-anderson.lizardo@openbossa.org>
Hi Lizardo,
On Tue, Jul 31, 2012, Anderson Lizardo wrote:
> Flags field has 32-bit size. Same issue was fixed for mgmtops in
> 1801a4d45d74c29cebacaab79a07e9961300be41.
> ---
>
> v2 -> v3: Fix another occurrence of same bug.
>
> monitor/control.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
Applied. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH 0/2] Support for reserving bandwidth on L2CAP socket
From: Manoj Sharma @ 2012-08-13 6:14 UTC (permalink / raw)
To: Luiz Augusto von Dentz
Cc: Mat Martineau, Marcel Holtmann, linux-bluetooth, Anurag Gupta
In-Reply-To: <CABBYNZLRdFMBtGJLmoMy4QhKaHs3RuHpyqdtsYF9SKC7Y6SGLg@mail.gmail.com>
Hi Luiz & Mat,
Sorry for responding late.
On 8/1/12, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
> Hi Mat,
>
> On Tue, Jul 31, 2012 at 7:58 PM, Mat Martineau <mathewm@codeaurora.org>
> wrote:
>>
>> Manoj and Luiz -
>>
>>
>> On Tue, 31 Jul 2012, Luiz Augusto von Dentz wrote:
>>
>>> Hi Manoj,
>>>
>>> On Tue, Jul 31, 2012 at 2:30 PM, Manoj Sharma <ursmanoj@gmail.com>
>>> wrote:
>>>>
>>>> Hi Luiz,
>>>>
>>>> On 7/30/12, Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
>>>>>
>>>>> Hi Manoj,
>>>>>
>>>>> On Mon, Jul 30, 2012 at 9:30 AM, Manoj Sharma <ursmanoj@gmail.com>
>>>>> wrote:
>>>>>>
>>>>>> One problem which I have faced using SO_PRIORITY is explained below.
>>>>>>
>>>>>> Suppose we have 2 links A & B and link A has higher priority than
>>>>>> link
>>>>>> B. And outgoing data transfer is active on both links. Now if device
>>>>>> on link A goes far, there would be lot of failures and number of
>>>>>> re-transmissions would increase for link A. Consequently at any time
>>>>>> host would have significant number of packets for link A, getting
>>>>>> accumulated due to poor quality of link.But since link A packets have
>>>>>> higher priority, link B packets would suffer infinitely as long as
>>>>>> link A packet queue in host is non-empty. Thus link B protocols may
>>>>>> fail due to timers expiring and finally disconnection at upper
>>>>>> layers.
>>>>>
>>>>>
>>>>> There is a mechanism to avoid starvation, also apparently you didn't
>>>>> study the code since the priority is per L2CAP channel not per link so
>>>>> we are able to prioritize per profile.
>>>>>
>>>> I would check how starvation is avoided. But for your information I
>>>> did observe starvation practically. And I know that priority is per
>>>> L2CAP. I mentioned links based on assumption that AVDTP and OBEX are
>>>> connected with different devices. Hence priority would result into
>>>> priority of connections in such case ;).
>>>
>>>
>>> There is no such thing of prioritize a connection, the algorithm used
>>> always check every channel of each connection and prioritize the
>>> channel. Maybe you are confusing what some controllers do, the
>>> controller has no idea what L2CAP channel has been configured it only
>>> knows about the ACL connections.
>>
>>
>> The current starvation avoidance algorithm works well as long as there is
>> data queued for all of the L2CAP channels and the controller is sending
>> packets regularly. It does seem to break down when the controller queue
>> gets stuck (see below).
>
> Indeed, but that is not the host stack fault, in fact it less likely
> that controller queue gonna get stuck with AVDTP than with OBEX since
> the latter tend to push data as fast as it can, also for AVDTP it
> should be possible to set a sensible flushable timeout. Maybe we could
> make use of SO_SNDTIMEO to actually set the flushable timeout?
>
>> I do see where a bad situation arises when the OBEX connection is stalled
>> and only queued OBEX data is available to the host stack HCI scheduler at
>> that instant. In that case, the controller queue could be completely
>> consumed by data for the stalled channel no matter what the priorities
>> are.
>> This could even happen when audio data is passed to the socket at exactly
>> the right time.
>>
>> If you're using OBEX-over-L2CAP, this could be partially addressed by
>> setting a flush timeout. However, it would still be possible to fill the
>> buffers with OBEX packets because non-flushable ERTM s-frames would
>> accumulate in the controller buffer.
>>
>> For traditional OBEX-over-RFCOMM, an OBEX packet sizes that are smaller
>> than
>> the controller buffer could help. This is a tradeoff against throughput.
>> It could work to send smaller OBEX packets when an AVDTP stream is
>> active,
>> even if a larger OBEX MTU was negotiated.
>
> Yep, in certain situations this may actually be unavoidable like in
> link loss, although we might be able to have a very small link
> supervision timeout.
>
>> It would be a big help if Manoj could post kernel logs showing us how the
>> HCI scheduler is actually behaving in the problem case.
>
> Good point.
>
>>
>> While I'm convinced that a problem exists here, I think it can be
>> addressed
>> using existing interfaces instead of adding a new one. For example, it
>> may
>> be reasonable to not fully utilize the controller buffer with data for
>> just
>> one ACL, or to use priority when looking at controller buffer
>> utilization.
>> Maybe an ACL could use all but one slot in the controller buffer, maybe
>> it
>> could only use half if there are multiple ACLs open. I don't think it
>> would
>> throttle throughput unless the system was so heavily loaded that it
>> couldn't
>> respond to number-of-completed-packets in time at BR/EDR data rates, and
>> in
>> that case there are bigger problems. It's pretty easy to test with
>> hdev->acl_pkts set to different values to see if using less of the buffer
>> impacts throughput.
>
> Well the problem may exist but as I said credit based algorithm would
> probably be overkill, in the other hand it maybe be useful to leave at
> least one slot for each connection whenever possible, but iirc it does
> impact the throughput specially on controller that does have big
> buffers.
>
>> Right now, one stalled ACL disrupts all data flow through the controller.
>> And that seems like a problem worth solving.
>
> I would go with link supervision timeout, specially in case of audio
> if the ACL got stalled for more than 2 seconds there is probably a
> problem and in most cases it is better to disconnect and route the
> audio back to the speakers.
>
This point is my whole concern. In the situation I faced, stalled ACL
(OBEX) was causing disruption to the flow of A2DP traffic, here even
high priority of AVDTP channel doesn't work once OBEX ACL has taken
all data credits.
Therefore we do need to devise a mechanism where one stalled ACL does
not disrupt other ACLs.
As per my understanding if there are any delays caused by stalled ACL
on others ACLs carrying non-AVDTP data, such delays are not quickly
visible to end user. E.g. in case of FTP user may feel that data
transfer is slow, however it may be understood to him that since he is
using two devices at a time, it is ok. But if the stalled ACL is
impacting other ACL carrying AVDTP data, delays caused would be
immediately visible to end-user in form of glitches in music
streaming.
Hence in my opinion if we simply provide a mechanism to avoid AVDTP
being impacted by stalled ACLs, we are done. I gave this solution by
providing L2CAP socket option to reserve a credit for AVDTP channel.
First please comment if reserving a credit for AVDTP channel is a bad
solution and if we can devise a better solution for seamless streaming
of AVDTP.
Of course we can find better ways to facilitate reservation for AVDTP
channels i.e. other than socket option. In this regard also,
suggestion or even direct solution is welcome.
>>
>> I agree that SO_PRIORITY is not the problem, but I don't think this can
>> be
>> fixed at the audio subsystem level either.
>>
>
> Im not absolutely sure, but it has been quite some time I don't
> experience such problems and I do use A2DP/AVDTP a lot, in fact last
> week Ive setup both sink and source simultaneously (phone -> pc ->
> headset) together with a file transfer and I didn't notice any
> problems.
>
> --
> Luiz Augusto von Dentz
>
Best regards,
Manoj
^ permalink raw reply
* gstreamer a2dpSource plugin
From: alistair.rodger @ 2012-08-12 16:38 UTC (permalink / raw)
To: linux-bluetooth
Hello,
I am looking for some help getting audio out of the bluez stack using
gstreamer? Are we still using an alsa source or should we be using the
MediaTransport file descriptor.
I am able to generate a sink file descriptor, using the simple-endpoint
script, but don't know which gstreamer plugin to use.
I am able stream to a device using the a2dpsink.
Sincerely,
alistair
^ permalink raw reply
* Re: [PATCH] add support bluetooth usb 0489:e046 Foxconn / Hon Hai
From: koko Aborigines @ 2012-08-12 16:22 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: padovan, linux-bluetooth, linux-kernel
In-Reply-To: <1344785716.1780.7.camel@aeonflux>
[-- Attachment #1: Type: text/plain, Size: 936 bytes --]
Hi,
Sorry for my mistake.
Signed-off-by: Watcharapol Tadtiang <7aborigines7@gmail.com>
Thank You.
On Sun, Aug 12, 2012 at 10:35 PM, Marcel Holtmann <marcel@holtmann.org>wrote:
> Hi,
>
> > $ usb-deveices
> > T: Bus=01 Lev=02 Prnt=02 Port=02 Cnt=03 Dev#= 5 Spd=12 MxCh= 0
> > D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
> > P: Vendor=0489 ProdID=e046 Rev=01.12
> > S: Manufacturer=Broadcom Corp
> > S: Product=BCM20702A0
> > S: SerialNumber=C01885F67F9E
> > C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA
> > I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none)
> > I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none)
> > I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
> > I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
> >
> > $ lsusb
> > Bus 001 Device 005: ID 0489:e046 Foxconn / Hon Hai
>
> you need a Signed-off-by here.
>
> Regards
>
> Marcel
>
>
>
[-- Attachment #2: Type: text/html, Size: 1598 bytes --]
^ permalink raw reply
* Re: [PATCH] add support bluetooth usb 0489:e046 Foxconn / Hon Hai
From: Marcel Holtmann @ 2012-08-12 15:35 UTC (permalink / raw)
To: aborigines; +Cc: padovan, linux-bluetooth, linux-kernel
In-Reply-To: <1344757304-11555-1-git-send-email-7aborigines7@gmail.com>
Hi,
> $ usb-deveices
> T: Bus=01 Lev=02 Prnt=02 Port=02 Cnt=03 Dev#= 5 Spd=12 MxCh= 0
> D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
> P: Vendor=0489 ProdID=e046 Rev=01.12
> S: Manufacturer=Broadcom Corp
> S: Product=BCM20702A0
> S: SerialNumber=C01885F67F9E
> C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA
> I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none)
> I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none)
> I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
> I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
>
> $ lsusb
> Bus 001 Device 005: ID 0489:e046 Foxconn / Hon Hai
you need a Signed-off-by here.
Regards
Marcel
^ permalink raw reply
* [PATCH] add support bluetooth usb 0489:e046 Foxconn / Hon Hai
From: aborigines @ 2012-08-12 7:41 UTC (permalink / raw)
To: marcel, padovan; +Cc: linux-bluetooth, linux-kernel, aborigines
$ usb-deveices
T: Bus=01 Lev=02 Prnt=02 Port=02 Cnt=03 Dev#= 5 Spd=12 MxCh= 0
D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=0489 ProdID=e046 Rev=01.12
S: Manufacturer=Broadcom Corp
S: Product=BCM20702A0
S: SerialNumber=C01885F67F9E
C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA
I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none)
I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none)
I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
$ lsusb
Bus 001 Device 005: ID 0489:e046 Foxconn / Hon Hai
---
drivers/bluetooth/btusb.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index fc4bcd6..fb54c70 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -110,6 +110,7 @@ static struct usb_device_id btusb_table[] = {
/* Foxconn - Hon Hai */
{ USB_DEVICE(0x0489, 0xe033) },
+ { USB_DEVICE(0x0489, 0xe046) },
{ } /* Terminating entry */
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/4] Bluetooth: On socket shutdown check rfcomm session and DLC exists
From: Dean Jenkins @ 2012-08-11 18:47 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344710830-10301-1-git-send-email-djenkins@mvista.com>
A race condition exists between near simultaneous asynchronous
DLC data channel disconnection requests from the host and remote device.
This causes the socket layer to request a socket shutdown at the same time
the rfcomm core is processing the disconnect request from the remote
device.
The socket layer retains a copy of a struct rfcomm_dlc d pointer.
The d pointer refers to a copy of a struct rfcomm_session.
When the socket layer thread performs a socket shutdown, the thread
may wait on a rfcomm lock in rfcomm_dlc_close(). This means that
whilst the thread waits, the rfcomm_session and/or rfcomm_dlc structures
pointed to by d maybe freed due to rfcomm core handling. Consequently,
when the rfcomm lock becomes available and the thread runs, a
malfunction could occur as a freed rfcomm_session pointer and/or a
freed d pointer will be erroneously reused.
Therefore, after the rfcomm lock is acquired, check that the struct
rfcomm_session is still valid by searching the rfcomm session list.
If the session is valid then validate the d pointer by searching the
rfcomm session list of active DLCs for the rfcomm_dlc structure
pointed by d.
If active DLCs exist when the rfcomm session is terminating,
avoid a memory leak of rfcomm_dlc structures by ensuring that
rfcomm_session_close() is used instead of rfcomm_session_del().
Signed-off-by: Dean Jenkins <djenkins@mvista.com>
---
net/bluetooth/rfcomm/core.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index c7921fd..1a7db34 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -496,11 +496,34 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
{
- int r;
+ int r = 0;
+ struct rfcomm_dlc *d_list;
+ struct rfcomm_session *s, *s_list;
+ struct list_head *p, *n, *p2, *n2;
rfcomm_lock();
- r = __rfcomm_dlc_close(d, err);
+ s = d->session;
+ if (s) {
+ /* check the session still exists after waiting on the mutex */
+ list_for_each_safe(p, n, &session_list) {
+ s_list = list_entry(p, struct rfcomm_session, list);
+ if (s == s_list) {
+ /* check the dlc still exists */
+ /* after waiting on the mutex */
+ list_for_each_safe(p2, n2, &s->dlcs) {
+ d_list = list_entry(p2,
+ struct rfcomm_dlc,
+ list);
+ if (d == d_list) {
+ r = __rfcomm_dlc_close(d, err);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
rfcomm_unlock();
return r;
@@ -1155,7 +1178,7 @@ static struct rfcomm_session *rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
break;
case BT_DISCONN:
- s = rfcomm_session_del(s);
+ s = rfcomm_session_close(s, ECONNRESET);
break;
}
}
--
1.7.10.1
^ permalink raw reply related
* [PATCH 3/4] Bluetooth: Avoid rfcomm_session_timeout using freed pointer
From: Dean Jenkins @ 2012-08-11 18:47 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344710830-10301-1-git-send-email-djenkins@mvista.com>
rfcomm_session_timeout() protects the scenario of the remote
Bluetooth device failing to send a DISC on the rfcomm control
channel after the last data DLC channel has been closed.
There is a race condition between the timer expiring causing
rfcomm_session_timeout() to run and the rfcomm session being
deleted. If the rfcomm session is deleted then
rfcomm_session_timeout() would use a freed rfcomm session
pointer resulting in a potential kernel crash or memory corruption.
Note the timer is cleared before the rfcomm session is deleted
by del_timer() so the circumstances for a failure to occur are
as follows:
rfcomm_session_timeout() needs to be executing before the
del_timer() is called to clear the timer but
rfcomm_session_timeout() needs to be delayed from using the
rfcomm session pointer until after the session has been deleted.
Therefore, there is a very small window of opportunity for failure.
The solution is to use del_timer_sync() instead of del_timer()
as this ensures that rfcomm_session_timeout() is not running
when del_timer_sync() returns. This means that it is not
possible for rfcomm_session_timeout() to run after the rfcomm
session has been deleted.
Signed-off-by: Dean Jenkins <djenkins@mvista.com>
---
net/bluetooth/rfcomm/core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 24d4d3c..c7921fd 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -264,8 +264,8 @@ static void rfcomm_session_clear_timer(struct rfcomm_session *s)
{
BT_DBG("session %p state %ld", s, s->state);
- if (timer_pending(&s->timer))
- del_timer(&s->timer);
+ /* ensure rfcomm_session_timeout() is not running past this point */
+ del_timer_sync(&s->timer);
}
/* ---- RFCOMM DLCs ---- */
--
1.7.10.1
^ permalink raw reply related
* [PATCH 2/4] Bluetooth: Return rfcomm session pointers to avoid freed session
From: Dean Jenkins @ 2012-08-11 18:47 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344710830-10301-1-git-send-email-djenkins@mvista.com>
Unfortunately, the design retains copies of the s rfcomm session
pointer in various code blocks and this invites the reuse of a
freed session pointer.
Therefore, return the rfcomm session pointer back up the call stack
to avoid reusing a freed rfcomm session pointer. When the rfcomm
session is deleted, NULL is passed up the call stack.
Signed-off-by: Dean Jenkins <djenkins@mvista.com>
---
net/bluetooth/rfcomm/core.c | 88 +++++++++++++++++++++++++++----------------
1 file changed, 55 insertions(+), 33 deletions(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index b0805c1..24d4d3c 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -83,7 +83,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
u8 sec_level,
int *err);
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
-static void rfcomm_session_del(struct rfcomm_session *s);
+static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s);
/* ---- RFCOMM frame parsing macros ---- */
#define __get_dlci(b) ((b & 0xfc) >> 2)
@@ -612,9 +612,13 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
return s;
}
-static void rfcomm_session_del(struct rfcomm_session *s)
+static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s)
{
- int state = s->state;
+ int state;
+
+ BUG_ON(s == NULL);
+
+ state = s->state;
BT_DBG("session %p state %ld", s, s->state);
@@ -626,6 +630,8 @@ static void rfcomm_session_del(struct rfcomm_session *s)
if (state != BT_LISTEN)
module_put(THIS_MODULE);
+
+ return NULL;
}
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
@@ -644,11 +650,14 @@ static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
return NULL;
}
-static void rfcomm_session_close(struct rfcomm_session *s, int err)
+static struct rfcomm_session *rfcomm_session_close(struct rfcomm_session *s,
+ int err)
{
struct rfcomm_dlc *d;
struct list_head *p, *n;
+ BUG_ON(s == NULL);
+
BT_DBG("session %p state %ld err %d", s, s->state, err);
s->state = BT_CLOSED;
@@ -660,7 +669,7 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
__rfcomm_dlc_close(d, err);
}
- rfcomm_session_del(s);
+ return rfcomm_session_del(s);
}
static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
@@ -712,8 +721,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
if (*err == 0 || *err == -EINPROGRESS)
return s;
- rfcomm_session_del(s);
- return NULL;
+ return rfcomm_session_del(s);
failed:
sock_release(sock);
@@ -1102,7 +1110,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
}
/* ---- RFCOMM frame reception ---- */
-static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
+static struct rfcomm_session *rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
{
BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
@@ -1111,7 +1119,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
if (!d) {
rfcomm_send_dm(s, dlci);
- return 0;
+ return s;
}
switch (d->state) {
@@ -1147,14 +1155,14 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
break;
case BT_DISCONN:
- rfcomm_session_del(s);
+ s = rfcomm_session_del(s);
break;
}
}
- return 0;
+ return s;
}
-static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
+static struct rfcomm_session *rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
{
int err = 0;
@@ -1179,12 +1187,13 @@ static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
err = ECONNRESET;
s->state = BT_CLOSED;
- rfcomm_session_close(s, err);
+ s = rfcomm_session_close(s, err);
}
- return 0;
+ return s;
}
-static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
+static struct rfcomm_session *rfcomm_recv_disc(struct rfcomm_session *s,
+ u8 dlci)
{
int err = 0;
@@ -1214,10 +1223,10 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
err = ECONNRESET;
s->state = BT_CLOSED;
- rfcomm_session_close(s, err);
+ s = rfcomm_session_close(s, err);
}
- return 0;
+ return s;
}
void rfcomm_dlc_accept(struct rfcomm_dlc *d)
@@ -1638,11 +1647,18 @@ drop:
return 0;
}
-static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
+static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s,
+ struct sk_buff *skb)
{
struct rfcomm_hdr *hdr = (void *) skb->data;
u8 type, dlci, fcs;
+ if (!s) {
+ /* no session, so free socket data */
+ kfree_skb(skb);
+ return s;
+ }
+
dlci = __get_dlci(hdr->addr);
type = __get_type(hdr->ctrl);
@@ -1653,7 +1669,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
if (__check_fcs(skb->data, type, fcs)) {
BT_ERR("bad checksum in packet");
kfree_skb(skb);
- return -EILSEQ;
+ return s;
}
if (__test_ea(hdr->len))
@@ -1669,22 +1685,23 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
case RFCOMM_DISC:
if (__test_pf(hdr->ctrl))
- rfcomm_recv_disc(s, dlci);
+ s = rfcomm_recv_disc(s, dlci);
break;
case RFCOMM_UA:
if (__test_pf(hdr->ctrl))
- rfcomm_recv_ua(s, dlci);
+ s = rfcomm_recv_ua(s, dlci);
break;
case RFCOMM_DM:
- rfcomm_recv_dm(s, dlci);
+ s = rfcomm_recv_dm(s, dlci);
break;
case RFCOMM_UIH:
- if (dlci)
- return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
-
+ if (dlci) {
+ rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
+ return s;
+ }
rfcomm_recv_mcc(s, skb);
break;
@@ -1693,7 +1710,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
break;
}
kfree_skb(skb);
- return 0;
+ return s;
}
/* ---- Connection and data processing ---- */
@@ -1775,6 +1792,8 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
struct rfcomm_dlc *d;
struct list_head *p, *n;
+ BUG_ON(s == NULL);
+
BT_DBG("session %p state %ld", s, s->state);
list_for_each_safe(p, n, &s->dlcs) {
@@ -1830,7 +1849,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
}
}
-static inline void rfcomm_process_rx(struct rfcomm_session *s)
+static inline struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s)
{
struct socket *sock = s->sock;
struct sock *sk = sock->sk;
@@ -1842,13 +1861,15 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
if (!skb_linearize(skb))
- rfcomm_recv_frame(s, skb);
+ s = rfcomm_recv_frame(s, skb);
else
kfree_skb(skb);
}
- if (sk->sk_state == BT_CLOSED)
- rfcomm_session_close(s, sk->sk_err);
+ if (s && (sk->sk_state == BT_CLOSED))
+ s = rfcomm_session_close(s, sk->sk_err);
+
+ return s;
}
static inline void rfcomm_accept_connection(struct rfcomm_session *s)
@@ -1902,7 +1923,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s)
case BT_CLOSED:
s->state = BT_CLOSED;
- rfcomm_session_close(s, sk->sk_err);
+ s = rfcomm_session_close(s, sk->sk_err);
break;
}
}
@@ -1934,11 +1955,12 @@ static inline void rfcomm_process_sessions(void)
break;
default:
- rfcomm_process_rx(s);
+ s = rfcomm_process_rx(s);
break;
}
- rfcomm_process_dlcs(s);
+ if (s)
+ rfcomm_process_dlcs(s);
}
rfcomm_unlock();
--
1.7.10.1
^ permalink raw reply related
* [PATCH 1/4] Bluetooth: Remove rfcomm session refcnt
From: Dean Jenkins @ 2012-08-11 18:47 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344710830-10301-1-git-send-email-djenkins@mvista.com>
The rfcomm session refcnt is unworkable as it is hard
to predict the program flow during abnormal protocol conditions
so is easy for the refcnt to be out-of-sync. In addition, high
processor loading can cause the run-time thread order to change
resulting in malfunctioning of the session refcnt eg. premature
session deletion or double session deletion resulting in
kernel crashes.
Therefore, rely on the rfcomm session state machine to absolutely
delete the rfcomm session at the right time. The rfcomm session
state machine is controlled by the DLC data channel connection
states. The rfcomm session is created when a DLC data channel is
required. The rfcomm session is deleted when all DLC data channels
are closed or in abnormal conditions when the socket is BT_CLOSED.
There are 4 connection / disconnection rfcomm session scenarios:
host initiated: host disconnected
host initiated: remote disconnected
remote initiated: host disconnected
remote initiated: remote disconnected
The connection procedures are independent of the disconnection
procedures. Strangely, the session refcnt was applying special
treatment so erroneously combining connection and disconnection
events.
Signed-off-by: Dean Jenkins <djenkins@mvista.com>
---
include/net/bluetooth/rfcomm.h | 6 -----
net/bluetooth/rfcomm/core.c | 56 +++++-----------------------------------
2 files changed, 6 insertions(+), 56 deletions(-)
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index e2e3eca..7afd419 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -158,7 +158,6 @@ struct rfcomm_session {
struct timer_list timer;
unsigned long state;
unsigned long flags;
- atomic_t refcnt;
int initiator;
/* Default DLC parameters */
@@ -276,11 +275,6 @@ static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src,
bdaddr_t *dst);
-static inline void rfcomm_session_hold(struct rfcomm_session *s)
-{
- atomic_inc(&s->refcnt);
-}
-
/* ---- RFCOMM sockets ---- */
struct sockaddr_rc {
sa_family_t rc_family;
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 8a60238..b0805c1 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -122,12 +122,6 @@ static inline void rfcomm_schedule(void)
wake_up_process(rfcomm_thread);
}
-static inline void rfcomm_session_put(struct rfcomm_session *s)
-{
- if (atomic_dec_and_test(&s->refcnt))
- rfcomm_session_del(s);
-}
-
/* ---- RFCOMM FCS computation ---- */
/* reversed, 8-bit, poly=0x07 */
@@ -263,16 +257,15 @@ static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
{
BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout);
- if (!mod_timer(&s->timer, jiffies + timeout))
- rfcomm_session_hold(s);
+ mod_timer(&s->timer, jiffies + timeout);
}
static void rfcomm_session_clear_timer(struct rfcomm_session *s)
{
BT_DBG("session %p state %ld", s, s->state);
- if (timer_pending(&s->timer) && del_timer(&s->timer))
- rfcomm_session_put(s);
+ if (timer_pending(&s->timer))
+ del_timer(&s->timer);
}
/* ---- RFCOMM DLCs ---- */
@@ -350,8 +343,6 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
{
BT_DBG("dlc %p session %p", d, s);
- rfcomm_session_hold(s);
-
rfcomm_session_clear_timer(s);
rfcomm_dlc_hold(d);
list_add(&d->list, &s->dlcs);
@@ -370,8 +361,6 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
if (list_empty(&s->dlcs))
rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT);
-
- rfcomm_session_put(s);
}
static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
@@ -631,9 +620,6 @@ static void rfcomm_session_del(struct rfcomm_session *s)
list_del(&s->list);
- if (state == BT_CONNECTED)
- rfcomm_send_disc(s, 0);
-
rfcomm_session_clear_timer(s);
sock_release(s->sock);
kfree(s);
@@ -665,8 +651,6 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
BT_DBG("session %p state %ld err %d", s, s->state, err);
- rfcomm_session_hold(s);
-
s->state = BT_CLOSED;
/* Close all dlcs */
@@ -676,8 +660,7 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
__rfcomm_dlc_close(d, err);
}
- rfcomm_session_clear_timer(s);
- rfcomm_session_put(s);
+ rfcomm_session_del(s);
}
static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
@@ -1164,18 +1147,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
break;
case BT_DISCONN:
- /* rfcomm_session_put is called later so don't do
- * anything here otherwise we will mess up the session
- * reference counter:
- *
- * (a) when we are the initiator dlc_unlink will drive
- * the reference counter to 0 (there is no initial put
- * after session_add)
- *
- * (b) when we are not the initiator rfcomm_rx_process
- * will explicitly call put to balance the initial hold
- * done after session add.
- */
+ rfcomm_session_del(s);
break;
}
}
@@ -1875,12 +1847,8 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
kfree_skb(skb);
}
- if (sk->sk_state == BT_CLOSED) {
- if (!s->initiator)
- rfcomm_session_put(s);
-
+ if (sk->sk_state == BT_CLOSED)
rfcomm_session_close(s, sk->sk_err);
- }
}
static inline void rfcomm_accept_connection(struct rfcomm_session *s)
@@ -1905,8 +1873,6 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
s = rfcomm_session_add(nsock, BT_OPEN);
if (s) {
- rfcomm_session_hold(s);
-
/* We should adjust MTU on incoming sessions.
* L2CAP MTU minus UIH header and FCS. */
s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu,
@@ -1954,7 +1920,6 @@ static inline void rfcomm_process_sessions(void)
if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
s->state = BT_DISCONN;
rfcomm_send_disc(s, 0);
- rfcomm_session_put(s);
continue;
}
@@ -1963,8 +1928,6 @@ static inline void rfcomm_process_sessions(void)
continue;
}
- rfcomm_session_hold(s);
-
switch (s->state) {
case BT_BOUND:
rfcomm_check_connection(s);
@@ -1976,8 +1939,6 @@ static inline void rfcomm_process_sessions(void)
}
rfcomm_process_dlcs(s);
-
- rfcomm_session_put(s);
}
rfcomm_unlock();
@@ -2027,7 +1988,6 @@ static int rfcomm_add_listener(bdaddr_t *ba)
if (!s)
goto failed;
- rfcomm_session_hold(s);
return 0;
failed:
sock_release(sock);
@@ -2085,8 +2045,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
if (!s)
return;
- rfcomm_session_hold(s);
-
list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
@@ -2118,8 +2076,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
}
- rfcomm_session_put(s);
-
rfcomm_schedule();
}
--
1.7.10.1
^ permalink raw reply related
* [PATCH 0/4] Bluetooth: Details of rfcomm fixes - remove session refcnt
From: Dean Jenkins @ 2012-08-11 18:47 UTC (permalink / raw)
To: linux-bluetooth
This patchset contains the following patches:
----------------------------------------------------------------
Dean Jenkins (4):
Bluetooth: Remove rfcomm session refcnt
Bluetooth: Return rfcomm session pointers to avoid freed session
Bluetooth: Avoid rfcomm_session_timeout using freed pointer
Bluetooth: On socket shutdown check rfcomm session and DLC exists
include/net/bluetooth/rfcomm.h | 6 ----
net/bluetooth/rfcomm/core.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------
2 files changed, 82 insertions(+), 87 deletions(-)
These rfcomm fixes includes a fix for a fundamental issue with the rfcomm
session refcnt that causes kernel crashes in high processor loaded
environments such as multi-core embedded ARM systems.
The concept of a refcnt is to increase the counter when something becomes
dependent on a resource. The counter is decreased when things no longer are
dependent on that resource. When the counter reaches zero, nothing is
dependent on the resource so the resource can be freed or released. The refcnt
should start with a value of 1 because something must be initially dependent on
the resource to prevent the resource from being immediately freed or released.
This means there must be 1 extra decrement operation when compared to the
number of increment operations (excluding the operation to set the initial
value of 1).
What does the rfcomm session refcnt protect ? This is unclear so here is
analysis of the locations of the calls to rfcomm_session_hold() that
increments the refcnt:
rfcomm_session_set_timer() - timer to force session disconnection when no DLCs
rfcomm_dlc_link() - binding DLC data channel to the session
rfcomm_session_close() - close the session but not delete session
rfcomm_accept_connection() - initialise refcnt to 1 for incoming connection
rfcomm_process_sessions() - protect processing of the session
rfcomm_add_listener() - initialise refcnt to 1 for listening session
rfcomm_security_cfm() - protect processing of the session
Lets go through the analysis of the rfcomm_session_hold() calls:
rfcomm_session_set_timer():
The refcnt is incremented when the rfcomm session timer is enabled. The timer
routine rfcomm_session_timeout() uses the session structure so the session
must not be deleted whilst the timer is enabled. This sounds like a valid
resource dependency, however, the timer is disabled each time the session is
closed or deleted. Therefore, protection of the session is unnecessary against
the timer expiring after the session has been deleted. It is noted that the
deletion of the timer is not SMP safe and a fix is supplied in this patchset.
rfcomm_dlc_link():
Each time a rfcomm DLC data connection is established, the refcnt is
incremented. This sounds like a valid resource dependency, however, the
rfcomm session is already dependent on DLC data channel connections because
there is a rfcomm_dlc list. In normal protocol operations, the rfcomm session is
deleted after the rfcomm control channel has been disconnected. The rfcomm
control channel is disconnected after all the rfcomm DLC data channels are
disconnected. Therefore, having a refcnt to protect against deletion of the
session whilst DLC data connections exist is unnecessary because a mechanism is
already in place.
rfcomm_session_close():
The call to rfcomm_session_hold() is matched by a call to rfcomm_session_put()
and protects the closing of DLC data connections. This looks like a
valid resource dependency to prevent the rfcomm session from being deleted
whilst closing the DLC data connections. However, rfcomm_session_close() is
called after the rfcomm control channel has disconnected or after the socket
layer has gone into a closed state (abnormal protocol handling). Therefore,
it seems that there is no risk of rfcomm_session_close() being called during
an active rfcomm control connection. This means protection of the rfcomm
session during the closing of any "orphaned" DLC data connection is
unnecessary.
rfcomm_accept_connection():
Each time an incoming rfcomm control channel connection request is detected, a
rfcomm session is created. The refcnt is set to 1 (via increment). This is
correct, however, it is not safe from thread context switching, see
below refcnt failure of rfcomm_security_cfm(). The refcnt should be set to 1
before the session is added to the session list to prevent premature deletion
of the rfcomm session due to other threads accessing the session list before
the initial increment has taken place. This is a race condition.
rfcomm_process_sessions():
The call to rfcomm_session_hold() is matched by a call to rfcomm_session_put()
and protects the calls to rfcomm_check_connection(), rfcomm_process_rx() and
rfcomm_process_dlcs(). This looks like a valid resource dependency. This is
hard to analyse. One observation is that the session cannot be deleted until
the rfcomm_session_put() is called, however, this assumes there is no
imbalance in the refcnt handling. Remember that a call to rfcomm_session_put()
will cause the session to be deleted when the refcnt hits zero. This makes the
code non-deterministic when considering abnormal protocol handling. In other
words, the session is deleted based on relative changes to the refcnt instead
of an absolute decisive reaction to an event to delete the session by the
session state machine.
rfcomm_add_listener():
A listening session is initially created. The refcnt is set to 1 (via
increment). This is correct, however, it is not safe from thread context
switching. The refcnt should be set to 1 before the session is added to the
session list to prevent premature deletion of the rfcomm session due to other
threads accessing the session list before the initial increment has taken place.
This is a race condition.
rfcomm_security_cfm():
The call to rfcomm_session_hold() is matched by a call to rfcomm_session_put()
and protects the operation of the list_for_each_safe(p, n, &s->dlcs) loop.
The protection is unnecessary because the loop does not modify the rfcomm
session structure. By experimentation, removal of the hold and put has no
impact and in fact prevents the scheduling while atomic warnings, see below.
Conclusions to what the refcnt is protecting
--------------------------------------------
Apart from doubts over the refcnt validity in rfcomm_process_sessions(), most of
the refcnt protection is duplicating existing protection mechanisms or is
setting the refcnt to an initial value of 1.
There is a fundamental flaw in the refcnt implementation. You will note that
the refcnt is not initially being set to 1 for host originated rfcomm control
channel connections. This means that there is an imbalance in the refcnt
treatment of host initiated and remote initiated rfcomm control channel
connections. It would appear that some workarounds in the disconnection code
were attempted (see below) that used the DLC initiator flag. These workarounds
are incorrect as the root cause is that the rfcomm session structure is not
added to the session list with a refcnt of 1. In other words, all rfcomm session
allocations should start with an initial refcnt of 1 and not 0. See above
description of how a refcnt should work.
IMHO the rfcomm session refcnt is adding extra code that is duplicating
existing protection mechanisms of the rfcomm core code. I believe the refcnt is
not adding anything useful to the solution and obscures the act of deleting the
rfcomm session structure. Is the refcnt worth fixing ? I think not, see
below for a solution as implemented by the patchset.
It could be argued that the refcnt and the rfcomm session state machine are
acting as a "belt and braces" solution. IMHO, the refcnt is therefore redundant
as shown by the solution in the patchset.
Note existing protection in rfcomm core includes the mutex rfcomm_lock() and
rfcomm_unlock() functions. This serialises the thread processing so only 1
rfcomm thread can run at any one time. The thread uses in a process context.
Note in kernel 2.6.34 this protection does not prevent rfcomm_security_cfm()
unning (uses interrupt context) however this was changed in later kernels.
Patchset solution
-----------------
The "fix" for the rfcomm session refcnt is to remove the refcnt for the
following reasons.
1. The lifetime of a rfcomm session refcnt does not last outside the lifetime
of its associated rfcomm session structure. This means the refcnt becomes
invalid as soon as the session is deleted. Consequently, the rfcomm session
refcnt does not manage the rfcomm session pointer after the session has been
deleted. This allows local copies of the rfcomm session s pointer to be reused
after the rfcomm session structure has been freed. In particular, additional
accesses to rfcomm_session_put() and rfcomm_session_hold() after the session has
been deleted will be using freed or reallocated memory. This can lead to kernel
crashes or memory corruption. Test debug added to the kernel confirmed that a
freed rfcomm session was sometimes being reused in rfcomm_session_put() and
rfcomm_session_hold() function calls. This may result in a kernel crash (shown
below) or memory corruption.
ARM Project Kernel 2.6.34 unpatched kernel crash:
[ 695.591056] Unable to handle kernel paging request at virtual address
00200200
[ 695.791122] [<802886c4>] (rfcomm_session_del+0x18/0x70) from [<8028a560>]
(rfcomm_run+0xf10/0x12d4)
[ 695.800260] [<8028a560>] (rfcomm_run+0xf10/0x12d4) from [<80065e70>]
(kthread+0x7c/0x84)
[ 695.808454] [<80065e70>] (kthread+0x7c/0x84) from [<8002db04>]
(kernel_thread_exit+0x0/0x8)
2. The initial rfcomm session refcnt is 0 or 1 depending of which rfcomm peer
initated the rfcomm session. This is incorrect because the rfcomm session
connection and disconnection events are independent of each other. In
other words, the refcnt value must reach the same value to allow a successful
disconnection despite which peer initiated the rfcomm session. This is a
fundamental flaw in the refcnt implementation.
3. The rfcomm session refcnt inhibits the existing rfcomm session state machine
from deleting the rfcomm session structure immediately the state machine knows
that the session is finished. I suspect this was to prevent the session timer
expiring after the session was finished. However, it is noted that the session
timer is deleted when the session is closed so the refcnt is unnecessary for
protection. One of the patches fixes the session timer deletion for SMP systems.
4. "Broken workaround" code becomes obvious when the rfcomm session refcnt
is removed. It can be seen that multiple attempts to fix the refcnt have been
tried but these attempts failed to fix the the refcnt initialisation issue so
are flawed. Therefore remove the workaround code to allow a proper fix.
5. High processor loading causes the kernel thread order to change exposing
the rfcomm session refcnt to malfunction eg. premature session deletion or
double session deletion. In particular, rfcomm_security_cfm() causes refcnt
failure by premature session deletion when the refcnt was initially zero.
This issue is improved in kernels later than 2.6.34 as rfcomm_security_cfm()
runs in a process context rather than in an interrupt context. This caused
scheduling while atomic warnings and kernel crashes see below.
ARM Project Kernel 2.6.34 unpatched kernel crash due to premature rfcomm
session deletion in rfcomm_security_cfm() because refcnt was initially zero so
the first pair of rfcomm_session_hold() and rfcomm_session_put() calls in
rfcomm_security_cfm() cause the session to be deleted early:
[ 165.033679] BUG: scheduling while atomic: uart/0/657/0x00000205
[ 165.070813] [<80032754>] (unwind_backtrace+0x0/0xec) from [<802ab928>]
(schedule+0x80/0x610)
[ 165.080075] [<802ab928>] (schedule+0x80/0x610) from [<802106a4>]
(lock_sock_nested+0x84/0xc4)
[ 165.089350] [<802106a4>] (lock_sock_nested+0x84/0xc4) from [<80283f1c>]
(l2cap_sock_shutdown+0x24/0x1e0)
[ 165.099554] [<80283f1c>] (l2cap_sock_shutdown+0x24/0x1e0) from [<802840f4>]
(l2cap_sock_release+0x1c/0x64)
[ 165.110542] [<802840f4>] (l2cap_sock_release+0x1c/0x64) from [<8020efbc>]
(sock_release+0x20/0xb8)
[ 165.120342] [<8020efbc>] (sock_release+0x20/0xb8) from [<80288844>]
(rfcomm_session_del+0x4c/0x70)
[ 165.130347] [<80288844>] (rfcomm_session_del+0x4c/0x70) from [<80288cd8>]
(rfcomm_security_cfm+0x158/0x194)
[ 165.141099] [<80288cd8>] (rfcomm_security_cfm+0x158/0x194) from [<80276c64>]
(hci_event_packet+0xc18/0x2f78)
[ 165.151760] [<80276c64>] (hci_event_packet+0xc18/0x2f78) from [<802737d4>]
(hci_rx_task+0xa4/0x254)
[ 165.161594] [<802737d4>] (hci_rx_task+0xa4/0x254) from [<80056568>]
(tasklet_action+0xa0/0x138)
[ 165.171096] [<80056568>] (tasklet_action+0xa0/0x138) from [<80056984>]
(__do_softirq+0x94/0x124)
[ 165.180657] [<80056984>] (__do_softirq+0x94/0x124) from [<80056ab0>]
(do_softirq+0x44/0x50)
[ 165.189662] [<80056ab0>] (do_softirq+0x44/0x50) from [<80056cec>]
(local_bh_enable_ip+0x94/0xc8)
[ 165.199323] [<80056cec>] (local_bh_enable_ip+0x94/0xc8) from [<801e34fc>]
(desc_get+0x84/0xf4)
[ 165.208640] [<801e34fc>] (desc_get+0x84/0xf4) from [<801e41ec>]
(prep_slave_sg+0xc4/0x23c)
[ 165.217627] [<801e41ec>] (prep_slave_sg+0xc4/0x23c) from [<801c2984>]
(tx_work_func+0x90/0x1c4)
[ 165.227149] [<801c2984>] (tx_work_func+0x90/0x1c4) from [<80062ab4>]
(worker_thread+0xfc/0x194)
[ 165.236621] [<80062ab4>] (worker_thread+0xfc/0x194) from [<80065d08>]
(kthread+0x7c/0x84)
[ 165.245567] [<80065d08>] (kthread+0x7c/0x84) from [<8002db04>]
(kernel_thread_exit+0x0/0x8)
Additional information about the patches:
1: Bluetooth: Remove rfcomm session refcnt
------------------------------------------
This patch removes the rfcomm session refcnt. It also removes suspected
workarounds as follows:
@@ -1164,18 +1147,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
break;
case BT_DISCONN:
- /* rfcomm_session_put is called later so don't do
- * anything here otherwise we will mess up the session
- * reference counter:
- *
- * (a) when we are the initiator dlc_unlink will drive
- * the reference counter to 0 (there is no initial put
- * after session_add)
- *
- * (b) when we are not the initiator rfcomm_rx_process
- * will explicitly call put to balance the initial hold
- * done after session add.
- */
+ rfcomm_session_del(s);
break;
This workaround was incorrect because disconnection of the rfcomm session does
not depend on which peer initiated the session. The initiator flag is for the
DLC data connections and is not for the rfcomm session control channel.
The solution is to delete the rfcomm session after the DISC-UA exchange on
the control channel. This is safe because there are no resource dependencies on
the delete at this point in the rfcomm session state machine.
@@ -1875,12 +1847,8 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
kfree_skb(skb);
}
- if (sk->sk_state == BT_CLOSED) {
- if (!s->initiator)
- rfcomm_session_put(s);
-
+ if (sk->sk_state == BT_CLOSED)
rfcomm_session_close(s, sk->sk_err);
- }
}
This workaround was incorrect because the rfcomm session control channel is
not dependent on the DLC initiator flag. This workaround is probably attempting
to compensate for the fundamental refcnt imbalance on host initiated rfcomm
control channel connections.
The solution is to close the rfcomm session if the socket is detected as
BT_CLOSED. This occurs when L2CAP has disconnected but the rfcomm layer never
performed the disconnection procedure of the rfcomm control channel
eg. abnormal protocol handling.
2: Bluetooth: Return rfcomm session pointers to avoid freed session
-------------------------------------------------------------------
This is the major improvement that prevents the rfcomm session pointer from
being reused after the rfcomm session has been deleted. This is done by passing
the rfcomm session pointer back up the call stack so ensures that the various
local s pointers are updated in the various code blocks.
Analysis of the changes highlights a malfunction in the original code:
@@ -1842,13 +1861,15 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
if (!skb_linearize(skb))
- rfcomm_recv_frame(s, skb);
+ s = rfcomm_recv_frame(s, skb);
else
kfree_skb(skb);
}
- if (sk->sk_state == BT_CLOSED)
- rfcomm_session_close(s, sk->sk_err);
+ if (s && (sk->sk_state == BT_CLOSED))
+ s = rfcomm_session_close(s, sk->sk_err);
+
+ return s;
}
It can be seen that rfcomm_recv_frame() can result in the rfcomm session being
deleted, for example, due to a rfcomm DISC on the rfcomm control channel. This
exposes the rfcomm_session_close(s, sk->sk_err) to fail because the local s is
now pointing to freed memory or reallocated memory. The solution in the new code
is to check that the s pointer is not NULL as this NULL indicates the rfcomm
session has been deleted. The original code had no mechanism to determine
whether the rfcomm session structure had been deleted.
Therefore, a crash was possible if both a rfcomm DISC on the rfcomm control
channel is processed and the socket transitions to BT_CLOSED. This can occur
in high processor loading conditions whereby rfcomm_process_rx() becomes
pre-empted after the DISC handling and sleeps. The socket transitions to
BT_CLOSED during the sleep. When rfcomm_process_rx() awakens, it crashes because
the s pointer is now invalid when used in rfcomm_session_close().
3: Bluetooth: Avoid rfcomm_session_timeout using freed pointer
--------------------------------------------------------------
This patch ensures that the rfcomm session timer is properly deleted in SMP
systems by using timer_del_sync(). This avoids having special treatment such
as the use of a refcnt, assuming that was the intention of the refcnt in the
first place.
4: Bluetooth: On socket shutdown check rfcomm session and DLC exists
--------------------------------------------------------------------
This patch prevents old pointers from the socket layer causing rfcomm crashes
during socket shutdown triggered from userland. The old pointers attempt
to disconnect no longer existing DLC connections.
ARM Project Kernel 2.6.34 unpatched kernel crash
[ 269.534202] Unable to handle kernel NULL pointer dereference at virtual
address 00000028
[ 269.784897] [<8020e9c8>] (sock_sendmsg+0x78/0xac) from [<8020ea3c>]
(kernel_sendmsg+0x40/0x7c)
[ 269.793614] [<8020ea3c>] (kernel_sendmsg+0x40/0x7c) from [<80289054>]
(rfcomm_send_frame+0x40/0x48)
[ 269.802743] [<80289054>] (rfcomm_send_frame+0x40/0x48) from [<802890c4>]
(rfcomm_send_disc+0x68/0x70)
[ 269.812045] [<802890c4>] (rfcomm_send_disc+0x68/0x70) from [<80289760>]
(__rfcomm_dlc_close+0x84/0x288)
[ 269.821519] [<80289760>] (__rfcomm_dlc_close+0x84/0x288) from [<80289988>]
(rfcomm_dlc_close+0x24/0x3c)
[ 269.830995] [<80289988>] (rfcomm_dlc_close+0x24/0x3c) from [<8028b9a4>]
(__rfcomm_sock_close+0x84/0x94)
[ 269.840489] [<8028b9a4>] (__rfcomm_sock_close+0x84/0x94) from [<8028b9f0>]
(rfcomm_sock_shutdown+0x3c/0x7c)
[ 269.850326] [<8028b9f0>] (rfcomm_sock_shutdown+0x3c/0x7c) from [<8020f008>]
(sys_shutdown+0x34/0x54)
[ 269.859554] [<8020f008>] (sys_shutdown+0x34/0x54) from [<8002d0a0>]
(ret_fast_syscall+0x0/0x30)
Testing
-------
Testing including field-trialling and IOP testing has been performed on a
patchset in a multi-core ARM using a 2.6.34 based kernel.
These tested patches have been forward ported to Linux 3.5-RC1 and are released
as a patchset. Basic tests on x86 have been done but it is difficult to
reproduce failure scenarios on a high performance x86 because timing is critical
to cause a malfunction of the unpatched code.
It should be noted that the rfcomm code has changed little between 2.6.34 and
3.5-RC1 with the exception of using process context instead of interrupt
context for all rfcomm core threads. This change may lower the risk of a rfcomm
session refcnt failure, in particular avoiding the rfcomm_security_cfm()
failure of scheduling while atomic.
I welcome discussion on these patches. I am keen to get these changes into
kernel.org. I am willing to re-factor the changes based on feedback from
the community.
I am on IRC in #bluez @ freenode with nick DeanJenkins if you wish to chat
to me about these patches.
Regards,
Dean Jenkins
MontaVista Software, LLC
^ permalink raw reply
* Bluetooth Device Class not detected properly. Can't even force through /etc/bluetooth/main.conf
From: Ryan @ 2012-08-11 2:32 UTC (permalink / raw)
To: linux-bluetooth
Sorry if this doesn't come out the way it's suppose to.....this is my
first time sending something to a mailing list
My problem relates to the bluetooth card in my Lenovo Thinkpad T500
(Broadcom BCM2046) not setting the correct device class, resulting in
a very limited number of services being loaded. The affected
distributions are Arch Linux and the Chakra Project (based off Arch
Linux), and I also talked with someone in #bluez who has the same
problem with a Marvell bluetooth card and Debian Linux. After the
bootup of Chakra, here's the output of 'hciconfig -a'
hci0: Type: BR/EDR Bus: USB
BD Address: 00:26:5E:BA:00:18 ACL MTU: 1021:8 SCO MTU: 64:1
UP RUNNING PSCAN ISCAN
RX bytes:1289 acl:0 sco:0 events:51 errors:0
TX bytes:1194 acl:0 sco:0 commands:51 errors:0
Features: 0xff 0xff 0x8f 0xfe 0x9b 0xff 0x79 0x83
Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
Link policy: RSWITCH HOLD SNIFF PARK
Link mode: SLAVE ACCEPT
Name: 'chakra-pc-0'
Class: 0x400100
Service Classes: Telephony
Device Class: Computer, Uncategorized
HCI Version: 2.1 (0x4) Revision: 0x518f
LMP Version: 2.1 (0x4) Subversion: 0x424c
Manufacturer: Broadcom Corporation (15)
Notice the Class field only says 0x400100. For me this only loads
Audio Sink and 2 other service. I should also note that I can set the
class by using 'hciconfig hci0 class 0x7e0100', however, it is always
changed back when stopping and starting bluetoothd. Setting 0x7e0100
as the default in main.conf also doesn't change the class the card
uses. Here's the output of 'bluetoothd -d -n'
[root@chakra-pc kurbster]# bluetoothd -d -n > bluetoothd
bluetoothd[2175]: Bluetooth daemon 4.99
bluetoothd[2175]: src/main.c:parse_config() parsing main.conf
bluetoothd[2175]: src/main.c:parse_config() discovto=0
bluetoothd[2175]: src/main.c:parse_config() pairto=0
bluetoothd[2175]: src/main.c:parse_config() pageto=8192
bluetoothd[2175]: src/main.c:parse_config() auto_to=60
bluetoothd[2175]: src/main.c:parse_config() name=%h-%d
bluetoothd[2175]: src/main.c:parse_config() class=0x7e0100
bluetoothd[2175]: src/main.c:parse_config() discov_interval=30
bluetoothd[2175]: src/main.c:parse_config() Key file does not have key
'DeviceID'
bluetoothd[2175]: Starting SDP server
bluetoothd[2175]: src/plugin.c:plugin_init() Loading builtin plugins
bluetoothd[2175]: src/plugin.c:add_plugin() Loading audio plugin
bluetoothd[2175]: src/plugin.c:add_plugin() Loading input plugin
bluetoothd[2175]: src/plugin.c:add_plugin() Loading serial plugin
bluetoothd[2175]: src/plugin.c:add_plugin() Loading network plugin
bluetoothd[2175]: src/plugin.c:add_plugin() Loading service plugin
bluetoothd[2175]: src/plugin.c:add_plugin() Loading hciops plugin
bluetoothd[2175]: src/plugin.c:add_plugin() Loading mgmtops plugin
bluetoothd[2175]: src/plugin.c:add_plugin() Loading formfactor plugin
bluetoothd[2175]: src/plugin.c:add_plugin() Loading storage plugin
bluetoothd[2175]: src/plugin.c:add_plugin() Loading adaptername plugin
bluetoothd[2175]: src/plugin.c:add_plugin() Loading wiimote plugin
bluetoothd[2175]: src/plugin.c:plugin_init() Loading plugins
/usr/lib/bluetooth/plugins
bluetoothd[2175]: plugins/service.c:register_interface() path
/org/bluez/2175/any
bluetoothd[2175]: plugins/service.c:register_interface() Registered
interface org.bluez.Service on path /org/bluez/2175/any
bluetoothd[2175]: network/manager.c:read_config()
/etc/bluetooth/network.conf: Key file does not have key
'DisableSecurity'
bluetoothd[2175]: network/manager.c:read_config() Config options: Security=true
bluetoothd[2175]: input/manager.c:input_manager_init() input.conf: Key
file does not have key 'IdleTimeout'
bluetoothd[2175]: audio/manager.c:audio_manager_init() audio.conf: Key
file does not have key 'AutoConnect'
bluetoothd[2175]: plugins/hciops.c:hciops_init()
bluetoothd[2175]: plugins/hciops.c:hciops_setup()
bluetoothd[2175]: src/main.c:main() Entering main loop
bluetoothd[2175]: src/rfkill.c:rfkill_event() RFKILL event idx 0 type
2 op 0 soft 0 hard 0
bluetoothd[2175]: src/rfkill.c:rfkill_event() RFKILL event idx 1 type
2 op 0 soft 0 hard 0
bluetoothd[2175]: src/rfkill.c:rfkill_event() RFKILL event idx 2 type
1 op 0 soft 0 hard 0
bluetoothd[2175]: plugins/hciops.c:init_known_adapters()
bluetoothd[2175]: plugins/hciops.c:init_device() hci0
bluetoothd[2175]: Listening for HCI events on hci0
bluetoothd[2175]: plugins/hciops.c:init_device() child 2176 forked
bluetoothd[2175]: plugins/hciops.c:read_local_features_complete() Got
features for hci0
bluetoothd[2175]: plugins/hciops.c:read_local_version_complete() Got
version for hci0
bluetoothd[2175]: plugins/hciops.c:read_bd_addr_complete() hci0 status 0
bluetoothd[2175]: plugins/hciops.c:read_bd_addr_complete() Got bdaddr for hci0
bluetoothd[2175]: plugins/hciops.c:read_local_name_complete() hci0 status 0
bluetoothd[2175]: plugins/hciops.c:read_local_name_complete() Got name for hci0
bluetoothd[2175]: plugins/hciops.c:read_tx_power_complete() hci0 status 0
bluetoothd[2175]: plugins/hciops.c:update_ext_inquiry_response() hci0
bluetoothd[2175]: plugins/hciops.c:read_local_ext_features_complete()
hci0 status 0
bluetoothd[2175]: HCI dev 0 up
bluetoothd[2175]: plugins/hciops.c:device_devup_setup() hci0
bluetoothd[2175]: src/adapter.c:btd_adapter_ref() 0x7f5c5619fd90: ref=1
bluetoothd[2175]: plugins/hciops.c:hciops_read_bdaddr() hci0
bluetoothd[2175]: src/sdpd-database.c:sdp_init_services_list()
bluetoothd[2175]: plugins/hciops.c:hciops_add_uuid() hci0
bluetoothd[2175]: plugins/hciops.c:update_service_classes() hci0 value 0
bluetoothd[2175]: plugins/hciops.c:hciops_add_uuid() hci0
bluetoothd[2175]: plugins/hciops.c:update_service_classes() hci0 value 0
bluetoothd[2175]: plugins/service.c:register_interface() path
/org/bluez/2175/hci0
bluetoothd[2175]: plugins/service.c:register_interface() Registered
interface org.bluez.Service on path /org/bluez/2175/hci0
bluetoothd[2175]: network/manager.c:network_server_probe() path
/org/bluez/2175/hci0
bluetoothd[2175]: src/adapter.c:btd_adapter_ref() 0x7f5c5619fd90: ref=2
bluetoothd[2175]: network/server.c:server_register() Registered
interface org.bluez.NetworkServer on path /org/bluez/2175/hci0
bluetoothd[2175]: serial/manager.c:proxy_probe() path /org/bluez/2175/hci0
bluetoothd[2175]: src/adapter.c:btd_adapter_ref() 0x7f5c5619fd90: ref=3
bluetoothd[2175]: serial/proxy.c:proxy_register() Registered interface
org.bluez.SerialProxyManager on path /org/bluez/2175/hci0
bluetoothd[2175]: src/adapter.c:btd_adapter_ref() 0x7f5c5619fd90: ref=4
bluetoothd[2175]: audio/manager.c:media_server_probe() path /org/bluez/2175/hci0
bluetoothd[2175]: src/adapter.c:btd_adapter_ref() 0x7f5c5619fd90: ref=5
bluetoothd[2175]: audio/manager.c:audio_adapter_ref() 0x7f5c561a0610: ref=1
bluetoothd[2175]: audio/manager.c:headset_server_probe() path
/org/bluez/2175/hci0
bluetoothd[2175]: audio/manager.c:audio_adapter_ref() 0x7f5c561a0610: ref=2
bluetoothd[2175]: audio/manager.c:headset_server_init() audio.conf:
Key file does not have key 'Master'
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Adding
record with handle 0x10000
bluetoothd[2175]: plugins/hciops.c:hciops_add_uuid() hci0
bluetoothd[2175]: plugins/hciops.c:update_service_classes() hci0 value 0
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00000003-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00000100-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00001002-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00001108-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00001112-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00001203-0000-1000-8000-00805f9
bluetoothd[2175]: audio/headset.c:headset_config_init() audio.conf:
Key file does not have key 'SCORouting'
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Adding
record with handle 0x10001
bluetoothd[2175]: plugins/hciops.c:hciops_add_uuid() hci0
bluetoothd[2175]: plugins/hciops.c:update_service_classes() hci0 value 64
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00000003-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00000100-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00001002-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 0000111e-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 0000111f-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00001203-0000-1000-8000-00805f9
bluetoothd[2175]: audio/manager.c:a2dp_server_probe() path /org/bluez/2175/hci0
bluetoothd[2175]: audio/manager.c:audio_adapter_ref() 0x7f5c561a0610: ref=3
bluetoothd[2175]: audio/a2dp.c:a2dp_register() audio.conf: Key file
does not have key 'Enable'
bluetoothd[2175]: audio/a2dp.c:a2dp_register() audio.conf: Key file
does not have key 'Disable'
bluetoothd[2175]: audio/avdtp.c:avdtp_init() audio.conf: Key file does
not have key 'Master'
bluetoothd[2175]: audio/manager.c:avrcp_server_probe() path /org/bluez/2175/hci0
bluetoothd[2175]: audio/manager.c:audio_adapter_ref() 0x7f5c561a0610: ref=4
bluetoothd[2175]: audio/avrcp.c:avrcp_register() audio.conf: Key file
does not have key 'Master'
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Adding
record with handle 0x10002
bluetoothd[2175]: plugins/hciops.c:hciops_add_uuid() hci0
bluetoothd[2175]: plugins/hciops.c:update_service_classes() hci0 value 64
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00000017-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00000100-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00001002-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 0000110c-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 0000110e-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Adding
record with handle 0x10003
bluetoothd[2175]: plugins/hciops.c:hciops_add_uuid() hci0
bluetoothd[2175]: plugins/hciops.c:update_service_classes() hci0 value 64
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00000017-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00000100-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 00001002-0000-1000-8000-00805f9
bluetoothd[2175]: src/sdpd-service.c:add_record_to_server() Record
pattern UUID 0000110e-0000-1000-8000-00805f9
bluetoothd[2175]: plugins/adaptername.c:adaptername_probe() Setting
name 'chakra-pc-0' for device 'hci0'
bluetoothd[2175]: plugins/hciops.c:hciops_set_name() hci0, name chakra-pc-0
bluetoothd[2175]: plugins/hciops.c:update_ext_inquiry_response() hci0
bluetoothd[2175]: plugins/formfactor.c:formfactor_probe() Setting
0x00010c for major/minor device class
bluetoothd[2175]: plugins/hciops.c:hciops_set_dev_class() hci0 major 1 minor 12
bluetoothd[2175]: plugins/hciops.c:hciops_unblock_device() hci0 dba
00:00:00:00:00:00
bluetoothd[2175]: plugins/hciops.c:hciops_load_keys() hci0 keys 0 debug_keys 0
bluetoothd[2175]: Unable to load keys to adapter_ops: Function not
implemented (38)
bluetoothd[2175]: plugins/hciops.c:hciops_get_conn_list() hci0
bluetoothd[2175]: src/manager.c:btd_manager_register_adapter() Adapter
/org/bluez/2175/hci0 registered
bluetoothd[2175]: src/adapter.c:btd_adapter_ref() 0x7f5c5619fd90: ref=6
bluetoothd[2175]: plugins/hciops.c:hciops_set_dev_class() hci0 major 1 minor 0
bluetoothd[2175]: audio/manager.c:state_changed() /org/bluez/2175/hci0
powered on
bluetoothd[2175]: audio/telephony.c:telephony_init()
bluetoothd[2175]: audio/headset.c:telephony_ready_ind() Telephony
plugin initialized
bluetoothd[2175]: audio/headset.c:print_ag_features() HFP AG features:
"Ability to reject a call" "Enhanced call status" "Extended Error
Result Codes"
bluetoothd[2175]: plugins/hciops.c:hciops_disable_cod_cache() hci0
cache_enable 1
bluetoothd[2175]: plugins/hciops.c:hciops_disable_cod_cache() hci0
current_cod 0x000000 wanted_cod 0x400100
bluetoothd[2175]: plugins/hciops.c:write_class() hci0 class 0x400100
bluetoothd[2175]: Adapter /org/bluez/2175/hci0 has been enabled
bluetoothd[2175]: plugins/hciops.c:hciops_set_discoverable() hci0 discoverable 1
bluetoothd[2175]: plugins/hciops.c:hciops_set_pairable() hci0 pairable 1
bluetoothd[2175]: src/adapter.c:btd_adapter_unref() 0x7f5c5619fd90: ref=5
bluetoothd[2175]: plugins/hciops.c:child_exit() child 2176 exited
bluetoothd[2175]: plugins/hciops.c:read_local_ext_features_complete()
hci0 status 0
bluetoothd[2175]: src/adapter.c:register_agent() Agent registered for
hci0 at :1.11:/blueDevil_agent
bluetoothd[2175]: plugins/hciops.c:read_tx_power_complete() hci0 status 0
bluetoothd[2175]: plugins/hciops.c:update_ext_inquiry_response() hci0
bluetoothd[2175]: plugins/hciops.c:update_ext_inquiry_response() hci0
bluetoothd[2175]: plugins/hciops.c:read_local_name_complete() hci0 status 0
bluetoothd[2175]: plugins/hciops.c:update_ext_inquiry_response() hci0
bluetoothd[2175]: plugins/hciops.c:read_simple_pairing_mode_complete()
hci0 status 0
bluetoothd[2175]: plugins/hciops.c:update_ext_inquiry_response() hci0
bluetoothd[2175]: plugins/hciops.c:read_scan_complete() hci0 status 0
bluetoothd[2175]: plugins/hciops.c:hciops_set_limited_discoverable()
hci0 limited 0
bluetoothd[2175]: src/adapter.c:adapter_mode_changed() old 0x00 new 0x03
bluetoothd[2175]: src/adapter.c:set_mode_complete()
^Cbluetoothd[2175]: Terminating
bluetoothd[2175]: src/adapter.c:adapter_remove() Removing adapter
/org/bluez/2175/hci0
bluetoothd[2175]: audio/manager.c:avrcp_server_remove() path
/org/bluez/2175/hci0
bluetoothd[2175]: src/sdpd-service.c:remove_record_from_server()
Removing record with handle 0x10003
bluetoothd[2175]: src/sdpd-service.c:remove_record_from_server()
Removing record with handle 0x10002
bluetoothd[2175]: audio/manager.c:audio_adapter_unref() 0x7f5c561a0610: ref=3
bluetoothd[2175]: audio/manager.c:a2dp_server_remove() path /org/bluez/2175/hci0
bluetoothd[2175]: audio/manager.c:audio_adapter_unref() 0x7f5c561a0610: ref=2
bluetoothd[2175]: audio/manager.c:headset_server_remove() path
/org/bluez/2175/hci0
bluetoothd[2175]: src/sdpd-service.c:remove_record_from_server()
Removing record with handle 0x10000
bluetoothd[2175]: src/sdpd-service.c:remove_record_from_server()
Removing record with handle 0x10001
bluetoothd[2175]: audio/manager.c:audio_adapter_unref() 0x7f5c561a0610: ref=1
bluetoothd[2175]: audio/manager.c:media_server_remove() path
/org/bluez/2175/hci0
bluetoothd[2175]: audio/manager.c:audio_adapter_unref() 0x7f5c561a0610: ref=0
bluetoothd[2175]: src/adapter.c:btd_adapter_unref() 0x7f5c5619fd90: ref=4
bluetoothd[2175]: src/adapter.c:btd_adapter_unref() 0x7f5c5619fd90: ref=3
bluetoothd[2175]: serial/manager.c:proxy_remove() path /org/bluez/2175/hci0
bluetoothd[2175]: src/adapter.c:btd_adapter_unref() 0x7f5c5619fd90: ref=2
bluetoothd[2175]: network/manager.c:network_server_remove() path
/org/bluez/2175/hci0
bluetoothd[2175]: network/server.c:path_unregister() Unregistered
interface org.bluez.NetworkServer on path /org/bluez/2175/hci0
bluetoothd[2175]: src/adapter.c:btd_adapter_unref() 0x7f5c5619fd90: ref=1
bluetoothd[2175]: plugins/service.c:unregister_interface() path
/org/bluez/2175/hci0
bluetoothd[2175]: plugins/hciops.c:hciops_power_off() hci0
bluetoothd[2175]: src/adapter.c:btd_adapter_unref() 0x7f5c5619fd90: ref=0
bluetoothd[2175]: src/agent.c:agent_release() Releasing agent :1.11,
/blueDevil_agent
bluetoothd[2175]: src/adapter.c:adapter_free() 0x7f5c5619fd90
bluetoothd[2175]: src/plugin.c:plugin_cleanup() Cleanup plugins
bluetoothd[2175]: plugins/service.c:unregister_interface() path
/org/bluez/2175/any
bluetoothd[2175]: plugins/hciops.c:hciops_exit()
bluetoothd[2175]: plugins/hciops.c:hciops_cleanup()
bluetoothd[2175]: Stopping hci0 event socket
bluetoothd[2175]: Stopping SDP server
bluetoothd[2175]: Exit
Here's where the fun comes in....Kubuntu detects the device class
correctly and loads all the services I ever need, including Obex.
Here's the output of 'hciconfig -a' on a Kubuntu LiveCD:
hci0: Type: BR/EDR Bus: USB
BD Address: 00:26:5E:BA:00:18 ACL MTU: 1021:8 SCO MTU: 64:1
UP RUNNING PSCAN
RX bytes:1145 acl:0 sco:0 events:41 errors:0
TX bytes:905 acl:0 sco:0 commands:41 errors:0
Features: 0xff 0xff 0x8f 0xfe 0x9b 0xff 0x79 0x83
Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
Link policy: RSWITCH HOLD SNIFF PARK
Link mode: SLAVE ACCEPT
Name: 'kubuntu-0'
Class: 0x7e0100
Service Classes: Networking, Rendering, Capturing, Object
Transfer, Audio, Telephony
Device Class: Computer, Uncategorized
HCI Version: 2.1 (0x4) Revision: 0x518f
LMP Version: 2.1 (0x4) Subversion: 0x424c
Manufacturer: Broadcom Corporation (15)
I'll be happy to provide any more info you may need to track down this
problem. And again, sorry for this being my first ever mailing list
post.
^ permalink raw reply
* [RFC 5/5] Bluetooth: Add set observer MGMT command
From: Jefferson Delfes @ 2012-08-10 21:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jefferson Delfes
In-Reply-To: <1344632507-21381-1-git-send-email-jefferson.delfes@openbossa.org>
This command will enable or disable observer mode. In that mode,
discovery will be started, so any broadcast will be received in device
found event.
Signed-off-by: Jefferson Delfes <jefferson.delfes@openbossa.org>
---
include/net/bluetooth/hci.h | 1 +
include/net/bluetooth/mgmt.h | 3 +++
net/bluetooth/mgmt.c | 43 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 47 insertions(+)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 80f585a..17ea1ad 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -119,6 +119,7 @@ enum {
HCI_PENDING_CLASS,
HCI_PERIODIC_INQ,
HCI_BROADCASTER,
+ HCI_OBSERVER,
};
/* HCI ioctl defines */
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 2e85012..69525f9 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -93,6 +93,7 @@ struct mgmt_rp_read_index_list {
#define MGMT_SETTING_HS 0x00000100
#define MGMT_SETTING_LE 0x00000200
#define MGMT_SETTING_BROADCASTER 0x00000400
+#define MGMT_SETTING_OBSERVER 0x00000800
#define MGMT_OP_READ_INFO 0x0004
#define MGMT_READ_INFO_SIZE 0
@@ -370,6 +371,8 @@ struct mgmt_cp_unset_controller_data {
#define MGMT_OP_SET_BROADCASTER 0x002B
+#define MGMT_OP_SET_OBSERVER 0x002C
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index ae4910a..845ce2d 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -380,6 +380,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
settings |= MGMT_SETTING_DISCOVERABLE;
settings |= MGMT_SETTING_PAIRABLE;
settings |= MGMT_SETTING_BROADCASTER;
+ settings |= MGMT_SETTING_OBSERVER;
if (lmp_ssp_capable(hdev))
settings |= MGMT_SETTING_SSP;
@@ -423,6 +424,9 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (test_bit(HCI_BROADCASTER, &hdev->dev_flags))
settings |= MGMT_SETTING_BROADCASTER;
+ if (test_bit(HCI_OBSERVER, &hdev->dev_flags))
+ settings |= MGMT_SETTING_OBSERVER;
+
if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
settings |= MGMT_SETTING_LINK_SECURITY;
@@ -2805,6 +2809,44 @@ failed:
return err;
}
+static int set_observer_le(struct hci_dev *hdev, u8 enable)
+{
+ struct hci_cp_le_set_scan_enable cmd;
+
+ cmd.enable = enable;
+ cmd.filter_dup = 0;
+ return hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cmd), &cmd);
+}
+
+static int set_observer(struct sock *sk, struct hci_dev *hdev, void *data,
+ u16 len)
+{
+ struct mgmt_mode *cp = data;
+ int err;
+
+ BT_DBG("%s val:%i", hdev->name, cp->val);
+
+ if (cp->val)
+ set_bit(HCI_OBSERVER, &hdev->dev_flags);
+ else
+ clear_bit(HCI_OBSERVER, &hdev->dev_flags);
+
+ hci_dev_lock(hdev);
+
+ if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
+ set_observer_le(hdev, cp->val);
+
+ err = send_settings_rsp(sk, MGMT_OP_SET_OBSERVER, hdev);
+ if (err < 0)
+ goto failed;
+
+ err = new_settings(hdev, sk);
+
+failed:
+ hci_dev_unlock(hdev);
+ return err;
+}
+
static const struct mgmt_handler {
int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len);
@@ -2855,6 +2897,7 @@ static const struct mgmt_handler {
{ set_controller_data, true, MGMT_SET_CONTROLLER_DATA_SIZE },
{ unset_controller_data, false, MGMT_UNSET_CONTROLLER_DATA_SIZE },
{ set_broadcaster, false, MGMT_SETTING_SIZE },
+ { set_observer, false, MGMT_SETTING_SIZE },
};
--
1.7.11.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