* Re: possible bug in blueZ 5.8 gatt tool or library
From: Anderson Lizardo @ 2014-02-07 0:55 UTC (permalink / raw)
To: Caleb Reinhold; +Cc: BlueZ development
In-Reply-To: <000001cf238d$a774e310$f65ea930$@lampreynetworks.com>
Hi,
On Thu, Feb 6, 2014 at 6:48 PM, Caleb Reinhold
<creinhold@lampreynetworks.com> wrote:
> It seemed that calling g_attrib_register() in the connection callback might
> be causing the client to start listening for indications and notifications
> too late, but registering right after the gatt_connect() call doesn't seem
> to help. Nor does placing a watch on the GIOChannel inside bt_io_connect(),
> so registering earlier doesn't appear to be the right approach. Do you know
> why we keep missing this initial indication on medium security, and how we
> might fix this issue?
If I remember correctly, the issue is in the kernel: if connect() is
called when security level is medium, the socket only gets POLLOUT
once SMP pairing finishes, and any ATT PDU received during that time
is lost.
Note that it's almost certain that your device is sending the
indication without requiring encryption. Otherwise, it would have sent
a Security Request (which triggers a Pairing Request from the Linux
side) and wait for the encryption to be enabled before sending the
indication. If that was the case, the kernel would deliver the ATT PDU
to gatttool after encryption is enabled and it would work as expected.
PS: Please, as common netiquette, avoid top-posting (i.e. answer
before the original message) and quote only the text that gives
context to your answer.
Best Regards,
--
Anderson Lizardo
http://www.indt.org/?lang=en
INdT - Manaus - Brazil
^ permalink raw reply
* BISECTED Re: 3.14-mw regression: circular locking dependency (&tty->legacy_mutex){+.+.+.}, at: [<ffffffff81ad6344>] tty_lock_nested+0x44/0xa0
From: Sander Eikelenboom @ 2014-02-07 0:37 UTC (permalink / raw)
To: Marcel Holtmann, gianluca
Cc: Greg Kroah-Hartman, linux-wireless, linux-bluetooth, linux-serial
In-Reply-To: <378824645.20140126114721@eikelenboom.it>
Hi Marcel / Gianluca,
Bisection points to this commit:
4a2fb3ecc7467c775b154813861f25a0ddc11aa0 is the first bad commit
commit 4a2fb3ecc7467c775b154813861f25a0ddc11aa0
Author: Gianluca Anzolin <gianluca@sottospazio.it>
Date: Mon Jan 6 21:23:52 2014 +0100
Bluetooth: Always wait for a connection on RFCOMM open()
This patch fixes two regressions introduced with the recent rfcomm tty
rework.
The current code uses the carrier_raised() method to wait for the
bluetooth connection when a process opens the tty.
However processes may open the port with the O_NONBLOCK flag or set the
CLOCAL termios flag: in these cases the open() syscall returns
immediately without waiting for the bluetooth connection to
complete.
This behaviour confuses userspace which expects an established bluetooth
connection.
The patch restores the old behaviour by waiting for the connection in
rfcomm_dev_activate() and removes carrier_raised() from the tty_port ops.
As a side effect the new code also fixes the case in which the rfcomm
tty device is created with the flag RFCOMM_REUSE_DLC: the old code
didn't call device_move() and ModemManager skipped the detection
probe. Now device_move() is always called inside rfcomm_dev_activate().
Signed-off-by: Gianluca Anzolin <gianluca@sottospazio.it>
Reported-by: Andrey Vihrov <andrey.vihrov@gmail.com>
Reported-by: Beson Chow <blc+bluez@mail.vanade.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
BTW perhaps time to update your tree ?
Bisection took me back to 3.12 like areas .. the risk of bisection failing of other unrelated bugs seems to increase that way
Sunday, January 26, 2014, 11:47:21 AM, you wrote:
> Hi,
> I have got a regression with a 3.14-mw kernel (last commit is 4ba9920e5e9c0e16b5ed24292d45322907bb9035)
> when a script is started that reads from serial over bluetooth, that wasn't in the 3.13 release kernel:
> Jan 26 11:36:10 serveerstertje kernel: [ 72.892926]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.900249] ======================================================
> Jan 26 11:36:10 serveerstertje kernel: [ 72.907697] [ INFO: possible circular locking dependency detected ]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.915214] 3.13.0-20140125-mw-pcireset+ #1 Not tainted
> Jan 26 11:36:10 serveerstertje kernel: [ 72.922307] -------------------------------------------------------
> Jan 26 11:36:10 serveerstertje kernel: [ 72.928315] zabbix_slimmeme/5909 is trying to acquire lock:
> Jan 26 11:36:10 serveerstertje kernel: [ 72.934323] (&tty->legacy_mutex){+.+.+.}, at: [<ffffffff81ad6344>] tty_lock_nested+0x44/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 72.940434]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.940434] but task is already holding lock:
> Jan 26 11:36:10 serveerstertje kernel: [ 72.952263] (&port->mutex){+.+.+.}, at: [<ffffffff81518aa7>] tty_port_open+0x67/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 72.958292]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.958292] which lock already depends on the new lock.
> Jan 26 11:36:10 serveerstertje kernel: [ 72.958292]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.976267]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.976267] the existing dependency chain (in reverse order) is:
> Jan 26 11:36:10 serveerstertje kernel: [ 72.988276]
> Jan 26 11:36:10 serveerstertje kernel: [ 72.988276] -> #1 (&port->mutex){+.+.+.}:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.000386] [<ffffffff81102dfd>] lock_acquire+0xcd/0x110
> Jan 26 11:36:10 serveerstertje kernel: [ 73.006526] [<ffffffff81ad3f97>] mutex_lock_nested+0x47/0x560
> Jan 26 11:36:10 serveerstertje kernel: [ 73.012612] [<ffffffff81518aa7>] tty_port_open+0x67/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.018637] [<ffffffff81aa4356>] rfcomm_tty_open+0x26/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.024674] [<ffffffff8150fcea>] tty_open+0x16a/0x5c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.030748] [<ffffffff811b4013>] chrdev_open+0xa3/0x1c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.036833] [<ffffffff811ad686>] do_dentry_open.isra.16+0x246/0x2f0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.043001] [<ffffffff811ad81d>] finish_open+0x1d/0x30
> Jan 26 11:36:10 serveerstertje kernel: [ 73.049106] [<ffffffff811befae>] do_last+0x7ce/0xdf0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.055191] [<ffffffff811bf68d>] path_openat+0xbd/0x6b0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.061211] [<ffffffff811c004e>] do_filp_open+0x3e/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.067177] [<ffffffff811aeaec>] do_sys_open+0x13c/0x230
> Jan 26 11:36:10 serveerstertje kernel: [ 73.073141] [<ffffffff811aebfd>] SyS_open+0x1d/0x20
> Jan 26 11:36:10 serveerstertje kernel: [ 73.079047] [<ffffffff81ad6f39>] system_call_fastpath+0x16/0x1b
> Jan 26 11:36:10 serveerstertje kernel: [ 73.084962]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.084962] -> #0 (&tty->legacy_mutex){+.+.+.}:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.096600] [<ffffffff8110230b>] __lock_acquire+0x1d4b/0x2220
> Jan 26 11:36:10 serveerstertje kernel: [ 73.102559] [<ffffffff81102dfd>] lock_acquire+0xcd/0x110
> Jan 26 11:36:10 serveerstertje kernel: [ 73.108475] [<ffffffff81ad3f97>] mutex_lock_nested+0x47/0x560
> Jan 26 11:36:10 serveerstertje kernel: [ 73.114419] [<ffffffff81ad6344>] tty_lock_nested+0x44/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.120354] [<ffffffff81ad63ab>] tty_lock+0xb/0x10
> Jan 26 11:36:10 serveerstertje kernel: [ 73.126258] [<ffffffff81aa4677>] rfcomm_dev_activate+0xb7/0x250
> Jan 26 11:36:10 serveerstertje kernel: [ 73.132222] [<ffffffff81518ad7>] tty_port_open+0x97/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.138195] [<ffffffff81aa4356>] rfcomm_tty_open+0x26/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.144207] [<ffffffff8150fcea>] tty_open+0x16a/0x5c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.150164] [<ffffffff811b4013>] chrdev_open+0xa3/0x1c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.156127] [<ffffffff811ad686>] do_dentry_open.isra.16+0x246/0x2f0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.162070] [<ffffffff811ad81d>] finish_open+0x1d/0x30
> Jan 26 11:36:10 serveerstertje kernel: [ 73.167933] [<ffffffff811befae>] do_last+0x7ce/0xdf0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.173787] [<ffffffff811bf68d>] path_openat+0xbd/0x6b0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.179600] [<ffffffff811c004e>] do_filp_open+0x3e/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.185302] [<ffffffff811aeaec>] do_sys_open+0x13c/0x230
> Jan 26 11:36:10 serveerstertje kernel: [ 73.190880] [<ffffffff811aebfd>] SyS_open+0x1d/0x20
> Jan 26 11:36:10 serveerstertje kernel: [ 73.196247] [<ffffffff81ad6f39>] system_call_fastpath+0x16/0x1b
> Jan 26 11:36:10 serveerstertje kernel: [ 73.201486]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.201486] other info that might help us debug this:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.201486]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.216718] Possible unsafe locking scenario:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.216718]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.226933] CPU0 CPU1
> Jan 26 11:36:10 serveerstertje kernel: [ 73.231978] ---- ----
> Jan 26 11:36:10 serveerstertje kernel: [ 73.237001] lock(&port->mutex);
> Jan 26 11:36:10 serveerstertje kernel: [ 73.241994] lock(&tty->legacy_mutex);
> Jan 26 11:36:10 serveerstertje kernel: [ 73.247043] lock(&port->mutex);
> Jan 26 11:36:10 serveerstertje kernel: [ 73.251999] lock(&tty->legacy_mutex);
> Jan 26 11:36:10 serveerstertje kernel: [ 73.256902]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.256902] *** DEADLOCK ***
> Jan 26 11:36:10 serveerstertje kernel: [ 73.256902]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.270890] 1 lock held by zabbix_slimmeme/5909:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.275398] #0: (&port->mutex){+.+.+.}, at: [<ffffffff81518aa7>] tty_port_open+0x67/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.280124]
> Jan 26 11:36:10 serveerstertje kernel: [ 73.280124] stack backtrace:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.289130] CPU: 5 PID: 5909 Comm: zabbix_slimmeme Not tainted 3.13.0-20140125-mw-pcireset+ #1
> Jan 26 11:36:10 serveerstertje kernel: [ 73.293860] Hardware name: MSI MS-7640/890FXA-GD70 (MS-7640) , BIOS V1.8B1 09/13/2010
> Jan 26 11:36:10 serveerstertje kernel: [ 73.298625] ffffffff826e2b70 ffff88005858f818 ffffffff81acbcfa ffff880057c72300
> Jan 26 11:36:10 serveerstertje kernel: [ 73.303571] ffffffff826e2b70 ffff88005858f868 ffffffff81ac7011 ffff880057c72300
> Jan 26 11:36:10 serveerstertje kernel: [ 73.308511] ffff880057c72300 ffff88005858f868 ffff880057c72ac0 0000000000000000
> Jan 26 11:36:10 serveerstertje kernel: [ 73.313325] Call Trace:
> Jan 26 11:36:10 serveerstertje kernel: [ 73.318092] [<ffffffff81acbcfa>] dump_stack+0x46/0x58
> Jan 26 11:36:10 serveerstertje kernel: [ 73.322900] [<ffffffff81ac7011>] print_circular_bug+0x2f6/0x32a
> Jan 26 11:36:10 serveerstertje kernel: [ 73.327723] [<ffffffff8110230b>] __lock_acquire+0x1d4b/0x2220
> Jan 26 11:36:10 serveerstertje kernel: [ 73.332545] [<ffffffff810fedbd>] ? trace_hardirqs_on+0xd/0x10
> Jan 26 11:36:10 serveerstertje kernel: [ 73.337414] [<ffffffff810e6141>] ? finish_task_switch+0x41/0xf0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.342279] [<ffffffff81ad0244>] ? sleep_on_timeout+0x4/0x20
> Jan 26 11:36:10 serveerstertje kernel: [ 73.347128] [<ffffffff81102dfd>] lock_acquire+0xcd/0x110
> Jan 26 11:36:10 serveerstertje kernel: [ 73.351950] [<ffffffff81ad6344>] ? tty_lock_nested+0x44/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.356792] [<ffffffff81ad3f97>] mutex_lock_nested+0x47/0x560
> Jan 26 11:36:10 serveerstertje kernel: [ 73.361599] [<ffffffff81ad6344>] ? tty_lock_nested+0x44/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.366363] [<ffffffff810fec6b>] ? trace_hardirqs_on_caller+0xfb/0x240
> Jan 26 11:36:10 serveerstertje kernel: [ 73.371200] [<ffffffff810fedbd>] ? trace_hardirqs_on+0xd/0x10
> Jan 26 11:36:10 serveerstertje kernel: [ 73.376030] [<ffffffff81ad6344>] tty_lock_nested+0x44/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.380842] [<ffffffff81ad63ab>] tty_lock+0xb/0x10
> Jan 26 11:36:10 serveerstertje kernel: [ 73.385616] [<ffffffff81aa4677>] rfcomm_dev_activate+0xb7/0x250
> Jan 26 11:36:10 serveerstertje kernel: [ 73.390398] [<ffffffff81ad4287>] ? mutex_lock_nested+0x337/0x560
> Jan 26 11:36:10 serveerstertje kernel: [ 73.395154] [<ffffffff810f90f0>] ? __init_waitqueue_head+0x60/0x60
> Jan 26 11:36:10 serveerstertje kernel: [ 73.399861] [<ffffffff81518ad7>] tty_port_open+0x97/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.404552] [<ffffffff81aa4356>] rfcomm_tty_open+0x26/0xe0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.409263] [<ffffffff8150fcea>] tty_open+0x16a/0x5c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.413954] [<ffffffff811b4013>] chrdev_open+0xa3/0x1c0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.418657] [<ffffffff81457bfd>] ? lockref_get+0x1d/0x30
> Jan 26 11:36:10 serveerstertje kernel: [ 73.423379] [<ffffffff811b3f70>] ? cdev_put+0x30/0x30
> Jan 26 11:36:10 serveerstertje kernel: [ 73.428056] [<ffffffff811ad686>] do_dentry_open.isra.16+0x246/0x2f0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.432768] [<ffffffff811ad81d>] finish_open+0x1d/0x30
> Jan 26 11:36:10 serveerstertje kernel: [ 73.437464] [<ffffffff811befae>] do_last+0x7ce/0xdf0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.442166] [<ffffffff811baff3>] ? inode_permission+0x13/0x50
> Jan 26 11:36:10 serveerstertje kernel: [ 73.446861] [<ffffffff811bb5ce>] ? link_path_walk+0x21e/0x880
> Jan 26 11:36:10 serveerstertje kernel: [ 73.451533] [<ffffffff810fec6b>] ? trace_hardirqs_on_caller+0xfb/0x240
> Jan 26 11:36:10 serveerstertje kernel: [ 73.456280] [<ffffffff811bf68d>] path_openat+0xbd/0x6b0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.461029] [<ffffffff8104cb03>] ? __do_page_fault+0x103/0x4e0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.465782] [<ffffffff81102e1d>] ? lock_acquire+0xed/0x110
> Jan 26 11:36:10 serveerstertje kernel: [ 73.470553] [<ffffffff811c004e>] do_filp_open+0x3e/0xa0
> Jan 26 11:36:10 serveerstertje kernel: [ 73.475321] [<ffffffff811cda31>] ? __alloc_fd+0xd1/0x120
> Jan 26 11:36:10 serveerstertje kernel: [ 73.480064] [<ffffffff811aeaec>] do_sys_open+0x13c/0x230
> Jan 26 11:36:10 serveerstertje kernel: [ 73.484743] [<ffffffff810fec6b>] ? trace_hardirqs_on_caller+0xfb/0x240
> Jan 26 11:36:10 serveerstertje kernel: [ 73.489470] [<ffffffff811aebfd>] SyS_open+0x1d/0x20
> Jan 26 11:36:10 serveerstertje kernel: [ 73.494191] [<ffffffff81ad6f39>] system_call_fastpath+0x16/0x1b
--
Best regards,
Sander mailto:linux@eikelenboom.it
^ permalink raw reply
* RE: possible bug in blueZ 5.8 gatt tool or library
From: Caleb Reinhold @ 2014-02-06 22:48 UTC (permalink / raw)
To: 'Anderson Lizardo'; +Cc: 'BlueZ development'
In-Reply-To: <CAJdJm_PEQEmCz1owo8MZ+29R-O5u8qm8x85WgeuKy9U1x74zGw@mail.gmail.com>
Hi Anderson,
Thanks for your advice. Connecting to the device on low security and then
switching to medium does allow gatttool to receive and confirm the
indication.
Our interest in gatttool is mainly as a demonstration of BlueZ's GATT API.
Our own GATT client application borrows heavily from gatttool and adds
features such as support for multiple simultaneous connections.
It seemed that calling g_attrib_register() in the connection callback might
be causing the client to start listening for indications and notifications
too late, but registering right after the gatt_connect() call doesn't seem
to help. Nor does placing a watch on the GIOChannel inside bt_io_connect(),
so registering earlier doesn't appear to be the right approach. Do you know
why we keep missing this initial indication on medium security, and how we
might fix this issue?
Thanks for your time,
Tom Harada
-----Original Message-----
From: Anderson Lizardo [mailto:anderson.lizardo@openbossa.org]
Sent: Tuesday, February 04, 2014 6:06 PM
To: Caleb Reinhold
Cc: BlueZ development
Subject: Re: possible bug in blueZ 5.8 gatt tool or library
Hi Caleb,
On Tue, Feb 4, 2014 at 5:12 PM, Caleb Reinhold
<creinhold@lampreynetworks.com> wrote:
> We are working with the 5.8 version of the library, kernel version
> 3.12.9, bluetoothctl, and gatttool when we encountered a possible error.
> We expected on the reconnection of two bonded devices, one of which
> had stored measurements, that data would transfer. When running gatt
> tool in medium security the first measurement to be indicated was lost.
First of all, gatttool is a developer tool, and it is far from being a
compliant GATT endpoint (e.g. it does not report to requests, which is
mandatory by the spec). With moderate effort though, the missing features
can be added.
> However upon attempting to reconnect to the simulated agent device
> with medium security two unexpected behaviors occurred. First, and
> more immediately apparent was that the simulated agent did not receive
> a confirmation of the indication. A slightly closer look using the
> hcidump, trying to find what had happened, showed that the indication
> had arrived at the hci layer but was not received at events_handler.
Are you using gatttool in interactive mode (i.e. the -I option) ? If yes,
try first connecting to the device with "connect" followed by setting the
security level to medium with "sec-level medium". This will imitate the
behavior of the BlueZ daemon when connecting to LE devices. Also be sure to
use the "--listen" option so the confirmation is sent by gatttool.
Let us know if it works :)
> While the indication
> is sent very swiftly upon the reconnection of the devices we
> understand this to be the manner in which low energy devices are
> supposed to behave given stored measurements and a bonded device.
You are correct that this is the expected behavior. But gatttool is far from
perfect. Did you try implementing a BlueZ plugin?
Best Regards,
--
Anderson Lizardo
http://www.indt.org/?lang=en
INdT - Manaus - Brazil
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth"
in the body of a message to majordomo@vger.kernel.org More majordomo info at
http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* FW: How to install bluez in Linux mint
From: Eric Shields @ 2014-02-06 22:21 UTC (permalink / raw)
To: linux-bluetooth
Sorry about that. No idea you didn't accept html. Below is the original
message in plain text, as is the rest of this email. I would NEVER be so
mean as to even attempt to send a virus or junk through your system. I just
need help, that's all. I shouldn't have used Gmail. Isn't configured for
plain text.
Thank you,
Eric Shields
Sent with Microsoft Outlook 2003
________________________________________
From: Eric Shields [mailto:skyvaleden0120@gmail.com]
Sent: Thursday, February 06, 2014 4:18 PM
To: linux-bluetooth@vger.kernel.org
Subject: How to install bluez in Linux mint
Hello, I am new to Linux but familiar with Android so I was wondering if any
help can be lent (so I can configure my Bluetooth adapter to be recognized
as a network adapter)? Please get back to me whenever possible.
Eric Shields
Sent via my Galaxy S Relay
via Gmail App
^ permalink raw reply
* [PATCH 6/6] android/a2dp: Fix audio deregistration
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
Unregistering a SEP can trigger abort_cfm callback if some device is
connected thus we should free setups list before all endpoints are
unregistered to avoid error in abort_cfm due to non-existing setup.
---
android/a2dp.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index f67a593..7a2f3cf 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -1483,12 +1483,12 @@ static void bt_audio_unregister(void)
if (audio_retry_id > 0)
g_source_remove(audio_retry_id);
- g_slist_free_full(setups, setup_free);
- setups = NULL;
-
g_slist_free_full(endpoints, unregister_endpoint);
endpoints = NULL;
+ g_slist_free_full(setups, setup_free);
+ setups = NULL;
+
audio_ipc_cleanup();
}
--
1.8.5.3
^ permalink raw reply related
* [PATCH 5/6] android/a2dp: Disconnect headset on IPC failure
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
In case audio IPC is suddenly disconnected (most likely due to crash of
mediaserver process) we should disconnect headset since it is no longer
associated with valid setup and cannot be used properly.
---
android/a2dp.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/android/a2dp.c b/android/a2dp.c
index 8eabfeb..f67a593 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -1515,6 +1515,7 @@ static gboolean audio_retry_register(void *data)
static void audio_disconnected(void *data)
{
+ GSList *l;
bool restart;
DBG("");
@@ -1526,6 +1527,12 @@ static void audio_disconnected(void *data)
bt_audio_unregister();
+ for (l = devices; l; l = g_slist_next(l)) {
+ struct a2dp_device *dev = l->data;
+
+ avdtp_shutdown(dev->session);
+ }
+
if (!restart)
return;
--
1.8.5.3
^ permalink raw reply related
* [PATCH 4/6] android/hal-audio: Write SBC parameters to logcat
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
---
android/hal-audio.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/android/hal-audio.c b/android/hal-audio.c
index 766327b..9312659 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -289,6 +289,78 @@ static int sbc_get_presets(struct audio_preset *preset, size_t *len)
return i;
}
+static int sbc_freq2int(uint8_t freq)
+{
+ switch (freq) {
+ case SBC_SAMPLING_FREQ_16000:
+ return 16000;
+ case SBC_SAMPLING_FREQ_32000:
+ return 32000;
+ case SBC_SAMPLING_FREQ_44100:
+ return 44100;
+ case SBC_SAMPLING_FREQ_48000:
+ return 48000;
+ default:
+ return 0;
+ }
+}
+
+static const char *sbc_mode2str(uint8_t mode)
+{
+ switch (mode) {
+ case SBC_CHANNEL_MODE_MONO:
+ return "Mono";
+ case SBC_CHANNEL_MODE_DUAL_CHANNEL:
+ return "DualChannel";
+ case SBC_CHANNEL_MODE_STEREO:
+ return "Stereo";
+ case SBC_CHANNEL_MODE_JOINT_STEREO:
+ return "JointStereo";
+ default:
+ return "(unknown)";
+ }
+}
+
+static int sbc_blocks2int(uint8_t blocks)
+{
+ switch (blocks) {
+ case SBC_BLOCK_LENGTH_4:
+ return 4;
+ case SBC_BLOCK_LENGTH_8:
+ return 8;
+ case SBC_BLOCK_LENGTH_12:
+ return 12;
+ case SBC_BLOCK_LENGTH_16:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+static int sbc_subbands2int(uint8_t subbands)
+{
+ switch (subbands) {
+ case SBC_SUBBANDS_4:
+ return 4;
+ case SBC_SUBBANDS_8:
+ return 8;
+ default:
+ return 0;
+ }
+}
+
+static const char *sbc_allocation2str(uint8_t allocation)
+{
+ switch (allocation) {
+ case SBC_ALLOCATION_SNR:
+ return "SNR";
+ case SBC_ALLOCATION_LOUDNESS:
+ return "Loudness";
+ default:
+ return "(unknown)";
+ }
+}
+
static void sbc_init_encoder(struct sbc_data *sbc_data)
{
a2dp_sbc_t *in = &sbc_data->sbc;
@@ -298,6 +370,15 @@ static void sbc_init_encoder(struct sbc_data *sbc_data)
out->endian = SBC_LE;
out->bitpool = in->max_bitpool;
+
+ DBG("frequency=%d channel_mode=%s block_length=%d subbands=%d "
+ "allocation=%s bitpool=%d-%d",
+ sbc_freq2int(in->frequency),
+ sbc_mode2str(in->channel_mode),
+ sbc_blocks2int(in->block_length),
+ sbc_subbands2int(in->subbands),
+ sbc_allocation2str(in->allocation_method),
+ in->min_bitpool, in->max_bitpool);
}
static int sbc_codec_init(struct audio_preset *preset, uint16_t mtu,
--
1.8.5.3
^ permalink raw reply related
* [PATCH 3/6] android/hal-audio: Ignore write call when closing
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
We should not try to neither auto-resume nor write when state is set to
NONE as this is case when we're being closed and it's ok do ignore
write request.
---
android/hal-audio.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/android/hal-audio.c b/android/hal-audio.c
index efdf823..766327b 100644
--- a/android/hal-audio.c
+++ b/android/hal-audio.c
@@ -831,6 +831,10 @@ static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
{
struct a2dp_stream_out *out = (struct a2dp_stream_out *) stream;
+ /* just return in case we're closing */
+ if (out->audio_state == AUDIO_A2DP_STATE_NONE)
+ return -1;
+
/* We can auto-start only from standby */
if (out->audio_state == AUDIO_A2DP_STATE_STANDBY) {
DBG("stream in standby, auto-start");
--
1.8.5.3
^ permalink raw reply related
* [PATCH 2/6] android/a2dp: Notify audio state on SEP close
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1391709250-8047-1-git-send-email-andrzej.kaczmarek@tieto.com>
---
android/a2dp.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 8d6e7bf..8eabfeb 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -990,6 +990,8 @@ static gboolean sep_close_ind(struct avdtp *session,
return FALSE;
}
+ bt_audio_notify_state(setup, HAL_AUDIO_STOPPED);
+
setup_remove(setup);
return TRUE;
@@ -1163,6 +1165,7 @@ static void sep_close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
void *user_data)
{
struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_setup *setup;
DBG("");
@@ -1171,7 +1174,16 @@ static void sep_close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
return;
}
- setup_remove_by_id(endpoint->id);
+ setup = find_setup(endpoint->id);
+ if (!setup) {
+ error("Unable to find stream setup for %u endpoint",
+ endpoint->id);
+ return;
+ }
+
+ bt_audio_notify_state(setup, HAL_AUDIO_STOPPED);
+
+ setup_remove(setup);
}
static void sep_abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
--
1.8.5.3
^ permalink raw reply related
* [PATCH 1/6] android/a2dp: Close AVDTP gracefully
From: Andrzej Kaczmarek @ 2014-02-06 17:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
When closing AVDTP we should wait for for CLOSE request to complete
(so stream go to idle state) before disconnecting signalling socket.
In case CLOSE is rejected, we simply abort stream.
---
android/a2dp.c | 4 +++-
android/avdtp.c | 21 +++++++++++++++++----
2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 8cff535..8d6e7bf 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -1166,8 +1166,10 @@ static void sep_close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
DBG("");
- if (err)
+ if (err) {
+ avdtp_abort(session, stream);
return;
+ }
setup_remove_by_id(endpoint->id);
}
diff --git a/android/avdtp.c b/android/avdtp.c
index e26d6ec..b9d1992 100644
--- a/android/avdtp.c
+++ b/android/avdtp.c
@@ -398,6 +398,8 @@ struct avdtp {
struct pending_req *req;
GSList *disconnect;
+
+ bool shutdown;
};
static GSList *lseps = NULL;
@@ -913,6 +915,11 @@ static void avdtp_sep_set_state(struct avdtp *session,
session->streams = g_slist_remove(session->streams, stream);
stream_free(stream);
}
+
+ if (session->io && session->shutdown && session->streams == NULL) {
+ int sock = g_io_channel_unix_get_fd(session->io);
+ shutdown(sock, SHUT_RDWR);
+ }
}
static void finalize_discovery(struct avdtp *session, int err)
@@ -2141,7 +2148,7 @@ gboolean avdtp_remove_disconnect_cb(struct avdtp *session, unsigned int id)
void avdtp_shutdown(struct avdtp *session)
{
GSList *l;
- int sock;
+ bool closing = false;
if (!session->io)
return;
@@ -2149,12 +2156,18 @@ void avdtp_shutdown(struct avdtp *session)
for (l = session->streams; l; l = g_slist_next(l)) {
struct avdtp_stream *stream = l->data;
- avdtp_close(session, stream, TRUE);
+ if (avdtp_close(session, stream, TRUE) == 0)
+ closing = true;
}
- sock = g_io_channel_unix_get_fd(session->io);
+ if (closing) {
+ /* defer shutdown until all streams closed */
+ session->shutdown = true;
+ } else {
+ int sock = g_io_channel_unix_get_fd(session->io);
- shutdown(sock, SHUT_RDWR);
+ shutdown(sock, SHUT_RDWR);
+ }
}
static void queue_request(struct avdtp *session, struct pending_req *req,
--
1.8.5.3
^ permalink raw reply related
* [RFC v8 06/10] Bluetooth: Introduce LE auto connection infrastructure
From: Andre Guedes @ 2014-02-06 17:35 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20140206160209.GA26623@molly>
This patch introduces the LE auto connection infrastructure which
will be used to implement the LE auto connection options.
In summary, the auto connection mechanism works as follows: Once the
first pending LE connection is created, the background scanning is
started. When the target device is found in range, the kernel
autonomously starts the connection attempt. If connection is
established successfully, that pending LE connection is deleted and
the background is stopped.
To achieve that, this patch introduces the hci_update_background_scan()
which controls the background scanning state. This function starts or
stops the background scanning based on the hdev->pend_le_conns list. If
there is no pending LE connection, the background scanning is stopped.
Otherwise, we start the background scanning.
Then, every time a pending LE connection is added we call hci_update_
background_scan() so the background scanning is started (in case it is
not already running). Likewise, every time a pending LE connection is
deleted we call hci_update_background_scan() so the background scanning
is stopped (in case this was the last pending LE connection) or it is
started again (in case we have more pending LE connections). Finally,
we also call hci_update_background_scan() in hci_le_conn_failed() so
the background scan is restarted in case the connection establishment
fails. This way the background scanning keeps running until all pending
LE connection are established.
Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
include/net/bluetooth/hci_core.h | 2 +
net/bluetooth/hci_conn.c | 5 +++
net/bluetooth/hci_core.c | 83 +++++++++++++++++++++++++++++++++++++++-
net/bluetooth/hci_event.c | 44 +++++++++++++++++++++
4 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 7b9c4ed..3c8dc0f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -778,6 +778,8 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
void hci_pend_le_conns_clear(struct hci_dev *hdev);
+void hci_update_background_scan(struct hci_dev *hdev);
+
int hci_uuids_clear(struct hci_dev *hdev);
int hci_link_keys_clear(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 70f4226..f3ca73f 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -527,6 +527,11 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
hci_proto_connect_cfm(conn, status);
hci_conn_del(conn);
+
+ /* Since we may have temporarily stopped the background scanning in
+ * favor of connection establishment, we should restart it.
+ */
+ hci_update_background_scan(hdev);
}
static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0f670bc..ff85205 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3021,7 +3021,7 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
entry = hci_pend_le_conn_lookup(hdev, addr, addr_type);
if (entry)
- return;
+ goto done;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
@@ -3035,6 +3035,9 @@ void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
list_add(&entry->list, &hdev->pend_le_conns);
BT_DBG("addr %pMR (type %u)", addr, addr_type);
+
+done:
+ hci_update_background_scan(hdev);
}
/* This function requires the caller holds hdev->lock */
@@ -3044,12 +3047,15 @@ void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
entry = hci_pend_le_conn_lookup(hdev, addr, addr_type);
if (!entry)
- return;
+ goto done;
list_del(&entry->list);
kfree(entry);
BT_DBG("addr %pMR (type %u)", addr, addr_type);
+
+done:
+ hci_update_background_scan(hdev);
}
/* This function requires the caller holds hdev->lock */
@@ -4597,3 +4603,76 @@ void hci_stop_le_scan_req(struct hci_request *req)
cp.enable = LE_SCAN_DISABLE;
hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
}
+
+static void update_background_scan_complete(struct hci_dev *hdev, u8 status)
+{
+ if (status)
+ BT_DBG("HCI request failed to update background scanning: "
+ "status 0x%2.2x", status);
+}
+
+/* This function controls the background scanning based on hdev->pend_le_conns
+ * list. If there are pending LE connection we start the background scanning,
+ * otherwise we stop it.
+ *
+ * This function requires the caller holds hdev->lock.
+ */
+void hci_update_background_scan(struct hci_dev *hdev)
+{
+ struct hci_cp_le_set_scan_param param_cp;
+ struct hci_cp_le_set_scan_enable enable_cp;
+ struct hci_request req;
+ struct hci_conn *conn;
+ int err;
+
+ hci_req_init(&req, hdev);
+
+ if (list_empty(&hdev->pend_le_conns)) {
+ /* If there is no pending LE connections, we should stop
+ * the background scanning.
+ */
+
+ /* If controller is not scanning we are done. */
+ if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+ return;
+
+ hci_stop_le_scan_req(&req);
+
+ BT_DBG("%s stopping background scanning", hdev->name);
+ } else {
+ /* If there is at least one pending LE connection, we should
+ * keep the background scan running.
+ */
+
+ /* If controller is already scanning we are done. */
+ if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+ return;
+
+ /* If controller is connecting, we should not start scanning
+ * since some controllers are not able to scan and connect at
+ * the same time.
+ */
+ conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+ if (conn)
+ return;
+
+ memset(¶m_cp, 0, sizeof(param_cp));
+ param_cp.type = LE_SCAN_PASSIVE;
+ param_cp.interval = cpu_to_le16(hdev->le_scan_interval);
+ param_cp.window = cpu_to_le16(hdev->le_scan_window);
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
+ ¶m_cp);
+
+ memset(&enable_cp, 0, sizeof(enable_cp));
+ enable_cp.enable = LE_SCAN_ENABLE;
+ enable_cp.filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+ &enable_cp);
+
+ BT_DBG("%s starting background scanning", hdev->name);
+ }
+
+ err = hci_req_run(&req, update_background_scan_complete);
+ if (err)
+ BT_ERR("Failed to run HCI request: err %d", err);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index df58cde..5796c06 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3620,25 +3620,69 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_proto_connect_cfm(conn, ev->status);
+ hci_pend_le_conn_del(hdev, &ev->bdaddr, ev->bdaddr_type);
+
unlock:
hci_dev_unlock(hdev);
}
+/* This function requires the caller holds hdev->lock */
+static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
+ u8 addr_type)
+{
+ struct hci_conn *conn;
+ u8 bdaddr_type;
+
+ if (!hci_pend_le_conn_lookup(hdev, addr, addr_type))
+ return;
+
+ if (addr_type == ADDR_LE_DEV_PUBLIC)
+ bdaddr_type = BDADDR_LE_PUBLIC;
+ else
+ bdaddr_type = BDADDR_LE_RANDOM;
+
+ conn = hci_connect(hdev, LE_LINK, addr, bdaddr_type, BT_SECURITY_LOW,
+ HCI_AT_NO_BONDING);
+ if (!IS_ERR(conn))
+ return;
+
+ switch (PTR_ERR(conn)) {
+ case -EBUSY:
+ /* If hci_connect() returns -EBUSY it means there is already
+ * an LE connection attempt going on. Since controllers don't
+ * support more than one connection attempt at the time, we
+ * don't consider this an error case.
+ */
+ break;
+ default:
+ BT_DBG("Failed to connect: err %ld", PTR_ERR(conn));
+ }
+}
+
static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
u8 num_reports = skb->data[0];
void *ptr = &skb->data[1];
s8 rssi;
+ hci_dev_lock(hdev);
+
while (num_reports--) {
struct hci_ev_le_advertising_info *ev = ptr;
+ if (ev->evt_type == LE_ADV_IND ||
+ ev->evt_type == LE_ADV_DIRECT_IND)
+ check_pending_le_conn(hdev, &ev->bdaddr,
+ ev->bdaddr_type);
+
rssi = ev->data[ev->length];
mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
NULL, rssi, 0, 1, ev->data, ev->length);
ptr += sizeof(*ev) + ev->length + 1;
}
+
+ hci_dev_unlock(hdev);
}
static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
--
1.8.5.3
^ permalink raw reply related
* Re: [RFC v8 06/10] Bluetooth: Introduce LE auto connection infrastructure
From: Andre Guedes @ 2014-02-06 17:34 UTC (permalink / raw)
To: Vinicius Costa Gomes; +Cc: linux-bluetooth
In-Reply-To: <20140206160209.GA26623@molly>
Hi Vinicius,
On Thu, 2014-02-06 at 14:02 -0200, Vinicius Costa Gomes wrote:
> Hi Andre,
>
> On 19:23 Wed 05 Feb, Andre Guedes wrote:
> > This patch introduces the LE auto connection infrastructure which
> > will be used to implement the LE auto connection options.
> >
> > In summary, the auto connection mechanism works as follows: Once the
> > first pending LE connection is created, the background scanning is
> > started. When the target device is found in range, the kernel
> > autonomously starts the connection attempt. If connection is
> > established successfully, that pending LE connection is deleted and
> > the background is stopped.
> >
> > To achieve that, this patch introduces the hci_update_background_scan()
> > which controls the background scanning state. This function starts or
> > stops the background scanning based on the hdev->pend_le_conns list. If
> > there is no pending LE connection, the background scanning is stopped.
> > Otherwise, we start the background scanning.
> >
> > Then, every time a pending LE connection is added we call hci_update_
> > background_scan() so the background scanning is started (in case it is
> > not already running). Likewise, every time a pending LE connection is
> > deleted we call hci_update_background_scan() so the background scanning
> > is stopped (in case this was the last pending LE connection) or it is
> > started again (in case we have more pending LE connections). Finally,
> > we also call hci_update_background_scan() in hci_le_conn_failed() so
> > the background scan is restarted in case the connection establishment
> > fails. This way the background scanning keeps running until all pending
> > LE connection are established.
> >
> > Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
> > ---
>
> [snip]
>
> > static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
> > {
> > u8 num_reports = skb->data[0];
> > void *ptr = &skb->data[1];
> > s8 rssi;
> >
> > + hci_dev_lock(hdev);
> > +
> > while (num_reports--) {
> > struct hci_ev_le_advertising_info *ev = ptr;
> >
> > + check_pending_le_conn(hdev, &ev->bdaddr, ev->bdaddr_type);
> > +
>
> Shouldn't the event type be checked to see if it is a connectable event?
Sure. I'm fixing it.
Thanks,
Andre
^ permalink raw reply
* Re: LE Connection Update Disallowed
From: Sandy Chapman @ 2014-02-06 16:21 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: BlueZ development
In-Reply-To: <CAJdJm_MScMpFNekv-9E3eFneNmLsgdurKb-R3kMTP66Gy40yaQ@mail.gmail.com>
Hi Anderson,
On Wed, Feb 5, 2014 at 11:23 AM, Anderson Lizardo
<anderson.lizardo@openbossa.org> wrote:
> HI Sandy,
>
> On Wed, Feb 5, 2014 at 10:51 AM, Sandy Chapman <schapman@lixar.com> wrote:
>>>> How do I initiate a Connection Update from the peripheral?
>>>
>>> I never tried this procedure myself, but my guess it that you are
>>> using the incorrect mechanism on the slave role. Take a look at the
>>> "Connection Parameters Update Request" on Vol 3, Part A, Section 4.20.
>>> I believe this is the correct way to request from the slave (from what
>>> I understand while reading the Linux kernel implementation of the
>>> master side).
>>>
>>> Note that when Linux is the master, this command is issued
>>> automatically by the kernel when requested by the slave.
>>
>> I've taken a look at that section and it appears that this is what is
>> used to trigger the Connection Update. It states that the command
>> shall only be issued from the slave to the master. I can confirm that
>> my device is in the slave role using 'hcitool con'.
>
> I think you didn't notice that the section I mentioned is about a
> L2CAP signalling packet, not an HCI command (which in this case is to
> be used on the master side). I suggest you read a bit more on the
> L2CAP section to understand how these signalling packets work. Then
> you can try building such packet with "hcitool cmd" (unless there is
> some support for it on the current kernel, which I didn't check)
>
Yes, you right, I missed that part. I've built out what my packet
should look like, but I'm having troubles sending it to the
controller. I really am stuck on issuing this packet. It appears that
I need to send an HCI ACL Data Packet which holds a Signalling
Command. This signalling command then holds the connection parameter
update request as it's payload. It looks like 'hcitool cmd' can't send
ACL packets though as the command requires an OGF and OCF which are
part of the HCI Command Packet, not the HCI ACL Data Packet. From what
I can tell, the best chance I'd have is to send it via the l2test tool
over L2CAP, but attempting to use le_public address type doesn't work
(which I believe will send the message over CID 0x0005 - the fixed LE
channel). It fails on getsockopt/setsockopt for the SOL_BLUETOOTH
type. From what I can tell, it requires a kernel with CoC (not sure
what it means or if I have it). I'm really hoping I'm not going to
have to compile the bluetooth kernel module myself to send this
connection update packet.
>>> You may want to take a look at the "GAP Peripheral Preferred
>>> Connection Parameters" characteristic (see Vol 3, Part C, Section
>>> 12.3). If iPhones reads this characteristic and honours the
>>> parameters, it may help.
>>
>> Unfortunately, it appears Apple explicitly ignores this parameter
>> (section 3.6 in this document
>> https://developer.apple.com/hardwaredrivers/BluetoothDesignGuidelines.pdf).
>
> This is unfortunate. It would be the easiest way to pass custom
> connection parameters IMHO.
>
>> I believe that 'hcitool lecup' is exactly supposed to initiate this
>> process. I've also tried to use 'hcitool cmd' to issue direct commands
>> to the controller (using Vol 3, Part A, Section 4.20 as a guide), but
>> I am having no luck. It's stating that the command is disallowed (not
>> that the parameters are invalid), so I'm guessing there's something
>> else wrong. Since this is directly communicating with the controller,
>> where would the problem be? In the kernel, itself? Could it be a
>> problem with the Broadcom chipset in my MacBook?
>
> "hcitool lecup" is just a helper, it uses the same mechanism that
> "hcitool cmd" uses (and both are just "raw" interfaces to the
> Bluetooth controller). If you are getting an "Invalid Parameters" on
> any of them, is either because you built the packet incorrectly on
> "hcitool cmd" or given invalid values as per the spec.
>
> By the way, I suggest using "btmon" instead of "hcidump", as the
> former has nicer output and is more up-to-date (although I'm not sure
> it supports parsing "LE Connection Update" parameters).
>
You're right btmon is much nicer and does support recognition of the
LE commands.
> Best Regards,
> --
> Anderson Lizardo
> http://www.indt.org/?lang=en
> INdT - Manaus - Brazil
I know what I'm doing might not be typical, but I really appreciate
your help. If there's any direction you could point me in, I'd be
really thankful. I don't really know what to try next.
Thanks again,
Sandy
--
^ permalink raw reply
* [PATCH 4/4] unit/avrcp: Add TP/MPS/BV-03-C test case
From: Andrei Emeltchenko @ 2014-02-06 16:06 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1391702774-18972-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that the Set Browsed Player command issued by the
AVRCP controller.
---
unit/test-avrcp.c | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 58e4c15..211ea36 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -330,6 +330,7 @@ static void execute_context(struct context *context)
}
#define AVRCP_SET_ADDRESSED_PLAYER 0x60
+#define AVRCP_SET_BROWSED_PLAYER 0x70
#if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -359,6 +360,13 @@ struct avrcp_header {
#error "Unknown byte order"
#endif
+struct avrcp_browsing_header {
+ uint8_t pdu_id;
+ uint16_t param_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_BROWSING_HEADER_LENGTH 3
+
static void set_company_id(uint8_t cid[3], const uint32_t cid_in)
{
cid[0] = cid_in >> 16;
@@ -386,6 +394,35 @@ static int avrcp_set_addr_player(struct context *context)
NULL, NULL);
}
+static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
+ uint8_t *operands,
+ size_t operand_count,
+ void *user_data)
+{
+ DBG("");
+
+ return FALSE;
+}
+
+static int avrcp_set_browsed_player(struct context *context)
+{
+ uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 2];
+ struct avrcp_browsing_header *pdu = (void *) buf;
+ struct avctp *session = context->dev->session;
+
+ DBG("");
+
+ memset(buf, 0, sizeof(buf));
+
+ pdu->pdu_id = AVRCP_SET_BROWSED_PLAYER;
+ pdu->params[0] = 0xab;
+ pdu->params[1] = 0xcd;
+ pdu->param_len = htons(2);
+
+ return avctp_send_browsing_req(session, buf, sizeof(buf),
+ avrcp_set_browsed_player_rsp, session);
+}
+
static void test_client(gconstpointer data)
{
struct context *context = create_context(0x0100, data);
@@ -394,6 +431,9 @@ static void test_client(gconstpointer data)
if (g_str_equal(context->data->test_name, "/TP/MPS/BV-01-C"))
ret = avrcp_set_addr_player(context);
+ if (g_str_equal(context->data->test_name, "/TP/MPS/BV-03-C"))
+ ret = avrcp_set_browsed_player(context);
+
DBG("ret = %d", ret);
g_assert(!ret);
@@ -415,5 +455,8 @@ int main(int argc, char *argv[])
0x00, 0x19, 0x58, 0x60, 0x00, 0x00,
0x02, 0xab, 0xcd));
+ define_test("/TP/MPS/BV-03-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x70, 0x00, 0x02,
+ 0xab, 0xcd));
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 3/4] unit/avrcp: Add support for browsing AVCTP channel
From: Andrei Emeltchenko @ 2014-02-06 16:06 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1391702774-18972-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
unit/test-avrcp.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 92 insertions(+), 4 deletions(-)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 7efdaea..58e4c15 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -47,6 +47,7 @@
struct test_pdu {
bool valid;
bool fragmented;
+ bool browse;
const uint8_t *data;
size_t size;
};
@@ -60,8 +61,10 @@ struct context {
GMainLoop *main_loop;
struct avrcp_device *dev;
guint source;
+ guint browse_source;
guint process;
int fd;
+ int browse_fd;
unsigned int pdu_offset;
const struct test_data *data;
};
@@ -75,6 +78,14 @@ struct context {
.size = sizeof(data(args)), \
}
+#define brs_pdu(args...) \
+ { \
+ .valid = true, \
+ .browse = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
#define frg_pdu(args...) \
{ \
.valid = true, \
@@ -130,7 +141,10 @@ static gboolean send_pdu(gpointer user_data)
pdu = &context->data->pdu_list[context->pdu_offset++];
- len = write(context->fd, pdu->data, pdu->size);
+ if (pdu->browse)
+ len = write(context->browse_fd, pdu->data, pdu->size);
+ else
+ len = write(context->fd, pdu->data, pdu->size);
if (g_test_verbose())
util_hexdump('<', pdu->data, len, test_debug, "AVCTP: ");
@@ -163,6 +177,8 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
ssize_t len;
int fd;
+ DBG("");
+
pdu = &context->data->pdu_list[context->pdu_offset++];
if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
@@ -190,23 +206,68 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
return TRUE;
}
+static gboolean browse_test_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ unsigned char buf[512];
+ ssize_t len;
+ int fd;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ context->browse_source = 0;
+ g_print("%s: cond %x\n", __func__, cond);
+ return FALSE;
+ }
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ len = read(fd, buf, sizeof(buf));
+
+ g_assert(len > 0);
+
+ if (g_test_verbose())
+ util_hexdump('>', buf, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
+
+ if (!pdu->fragmented)
+ context_process(context);
+
+ return TRUE;
+}
+
static struct context *create_context(uint16_t version, gconstpointer data)
{
struct context *context = g_new0(struct context, 1);
+ struct avctp *session;
GIOChannel *channel;
int err, sv[2];
bdaddr_t dst = {};
+ int ret;
+
+ DBG("");
context->main_loop = g_main_loop_new(NULL, FALSE);
g_assert(context->main_loop);
+ /* Control channel setup */
+
err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
- g_assert(err == 0);
+ g_assert(!err);
context->dev = avrcp_device_new(&dst);
- context->dev->session = avctp_new(sv[0], 672, 672, version);
- g_assert(context->dev->session != NULL);
+ g_assert(context->dev);
+ session = avctp_new(sv[0], 672, 672, version);
+ g_assert(session);
+
+ context->dev->session = session;
channel = g_io_channel_unix_new(sv[1]);
g_io_channel_set_close_on_unref(channel, TRUE);
@@ -221,6 +282,30 @@ static struct context *create_context(uint16_t version, gconstpointer data)
g_io_channel_unref(channel);
context->fd = sv[1];
+
+ /* Browsing channel setup */
+
+ err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+ g_assert(!err);
+
+ ret = avctp_connect_browsing(session, sv[0], 672, 672);
+ g_assert(!ret);
+
+ channel = g_io_channel_unix_new(sv[1]);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ context->browse_source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ browse_test_handler, context);
+ g_assert(context->browse_source > 0);
+
+ g_io_channel_unref(channel);
+
+ context->browse_fd = sv[1];
+
context->data = data;
return context;
@@ -233,6 +318,9 @@ static void execute_context(struct context *context)
if (context->source > 0)
g_source_remove(context->source);
+ if (context->browse_source > 0)
+ g_source_remove(context->browse_source);
+
avrcp_device_free(context->dev);
g_main_loop_unref(context->main_loop);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 2/4] unit/avrcp: First unit test for AVRCP profile
From: Andrei Emeltchenko @ 2014-02-06 16:06 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1391702774-18972-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test TP/MPS/BV-01-C [SetAddressedPlayer – CT] verifies
SetAddressedPlayer command.
---
Makefile.am | 9 ++
unit/test-avrcp.c | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 340 insertions(+)
create mode 100644 unit/test-avrcp.c
diff --git a/Makefile.am b/Makefile.am
index 1a44a9f..67b7167 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -281,6 +281,15 @@ unit_test_avctp_SOURCES = unit/test-avctp.c \
android/avctp.c android/avctp.h
unit_test_avctp_LDADD = @GLIB_LIBS@
+unit_tests += unit/test-avrcp
+
+unit_test_avrcp_SOURCES = unit/test-avrcp.c \
+ src/shared/util.h src/shared/util.c \
+ src/log.h src/log.c \
+ android/avctp.c android/avctp.h \
+ android/avrcp-lib.c android/avrcp-lib.h
+unit_test_avrcp_LDADD = @GLIB_LIBS@ lib/libbluetooth-internal.la
+
unit_tests += unit/test-gdbus-client
unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
new file mode 100644
index 0000000..7efdaea
--- /dev/null
+++ b/unit/test-avrcp.c
@@ -0,0 +1,331 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "src/log.h"
+#include "lib/bluetooth.h"
+
+#include "android/avctp.h"
+#include "android/avrcp-lib.h"
+
+#define IEEEID_BTSIG 0x001958
+
+struct test_pdu {
+ bool valid;
+ bool fragmented;
+ const uint8_t *data;
+ size_t size;
+};
+
+struct test_data {
+ char *test_name;
+ struct test_pdu *pdu_list;
+};
+
+struct context {
+ GMainLoop *main_loop;
+ struct avrcp_device *dev;
+ guint source;
+ guint process;
+ int fd;
+ unsigned int pdu_offset;
+ const struct test_data *data;
+};
+
+#define data(args...) ((const unsigned char[]) { args })
+
+#define raw_pdu(args...) \
+ { \
+ .valid = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
+#define frg_pdu(args...) \
+ { \
+ .valid = true, \
+ .fragmented = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
+#define define_test(name, function, args...) \
+ do { \
+ const struct test_pdu pdus[] = { \
+ args, { } \
+ }; \
+ static struct test_data data; \
+ data.test_name = g_strdup(name); \
+ data.pdu_list = g_malloc(sizeof(pdus)); \
+ memcpy(data.pdu_list, pdus, sizeof(pdus)); \
+ g_test_add_data_func(name, &data, function); \
+ } while (0)
+
+static void test_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ g_print("%s%s\n", prefix, str);
+}
+
+static void test_free(gconstpointer user_data)
+{
+ const struct test_data *data = user_data;
+
+ g_free(data->test_name);
+ g_free(data->pdu_list);
+}
+
+static gboolean context_quit(gpointer user_data)
+{
+ struct context *context = user_data;
+
+ if (context->process > 0)
+ g_source_remove(context->process);
+
+ g_main_loop_quit(context->main_loop);
+
+ return FALSE;
+}
+
+static gboolean send_pdu(gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ ssize_t len;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ len = write(context->fd, pdu->data, pdu->size);
+
+ if (g_test_verbose())
+ util_hexdump('<', pdu->data, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ if (pdu->fragmented)
+ return send_pdu(user_data);
+
+ context->process = 0;
+ return FALSE;
+}
+
+static void context_process(struct context *context)
+{
+ if (!context->data->pdu_list[context->pdu_offset].valid) {
+ context_quit(context);
+ return;
+ }
+
+ context->process = g_idle_add(send_pdu, context);
+}
+
+static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ unsigned char buf[512];
+ ssize_t len;
+ int fd;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ context->source = 0;
+ g_print("%s: cond %x\n", __func__, cond);
+ return FALSE;
+ }
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ len = read(fd, buf, sizeof(buf));
+
+ g_assert(len > 0);
+
+ if (g_test_verbose())
+ util_hexdump('>', buf, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
+
+ if (!pdu->fragmented)
+ context_process(context);
+
+ return TRUE;
+}
+
+static struct context *create_context(uint16_t version, gconstpointer data)
+{
+ struct context *context = g_new0(struct context, 1);
+ GIOChannel *channel;
+ int err, sv[2];
+ bdaddr_t dst = {};
+
+ context->main_loop = g_main_loop_new(NULL, FALSE);
+ g_assert(context->main_loop);
+
+ err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+ g_assert(err == 0);
+
+ context->dev = avrcp_device_new(&dst);
+ context->dev->session = avctp_new(sv[0], 672, 672, version);
+ g_assert(context->dev->session != NULL);
+
+ channel = g_io_channel_unix_new(sv[1]);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ context->source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ test_handler, context);
+ g_assert(context->source > 0);
+
+ g_io_channel_unref(channel);
+
+ context->fd = sv[1];
+ context->data = data;
+
+ return context;
+}
+
+static void execute_context(struct context *context)
+{
+ g_main_loop_run(context->main_loop);
+
+ if (context->source > 0)
+ g_source_remove(context->source);
+
+ avrcp_device_free(context->dev);
+
+ g_main_loop_unref(context->main_loop);
+
+ test_free(context->data);
+ g_free(context);
+}
+
+#define AVRCP_SET_ADDRESSED_PLAYER 0x60
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avrcp_header {
+ uint8_t company_id[3];
+ uint8_t pdu_id;
+ uint8_t packet_type:2;
+ uint8_t rsvd:6;
+ uint16_t params_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avrcp_header {
+ uint8_t company_id[3];
+ uint8_t pdu_id;
+ uint8_t rsvd:6;
+ uint8_t packet_type:2;
+ uint16_t params_len;
+ uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#else
+#error "Unknown byte order"
+#endif
+
+static void set_company_id(uint8_t cid[3], const uint32_t cid_in)
+{
+ cid[0] = cid_in >> 16;
+ cid[1] = cid_in >> 8;
+ cid[2] = cid_in;
+}
+
+static int avrcp_set_addr_player(struct context *context)
+{
+ uint8_t buf[AVRCP_HEADER_LENGTH + 2];
+ struct avrcp_header *pdu = (void *) buf;
+ struct avctp *session = context->dev->session;
+
+ memset(buf, 0, sizeof(buf));
+
+ set_company_id(pdu->company_id, IEEEID_BTSIG);
+
+ pdu->pdu_id = AVRCP_SET_ADDRESSED_PLAYER;
+ pdu->params[0] = 0xab;
+ pdu->params[1] = 0xcd;
+ pdu->params_len = htons(2);
+
+ return avctp_send_vendordep_req(session, AVC_CTYPE_CONTROL,
+ AVC_SUBUNIT_PANEL, buf, sizeof(buf),
+ NULL, NULL);
+}
+
+static void test_client(gconstpointer data)
+{
+ struct context *context = create_context(0x0100, data);
+ int ret = 0;
+
+ if (g_str_equal(context->data->test_name, "/TP/MPS/BV-01-C"))
+ ret = avrcp_set_addr_player(context);
+
+ DBG("ret = %d", ret);
+
+ g_assert(!ret);
+
+ execute_context(context);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+
+ if (g_test_verbose())
+ __btd_log_init("*", 0);
+
+ /* Media Player Selection Commands and Notifications tests */
+
+ define_test("/TP/MPS/BV-01-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48, 0x00,
+ 0x00, 0x19, 0x58, 0x60, 0x00, 0x00,
+ 0x02, 0xab, 0xcd));
+
+ return g_test_run();
+}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 1/4] android/avrcp: Decouple AVRCP logic from btio
From: Andrei Emeltchenko @ 2014-02-06 16:06 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
The patch makes AVRCP to be channel-agnostic so that it might be used in
unit tests. The idea is that all AVRCP logic would come to avrcp-lib and
channel stuff got to avrcp.
---
android/Android.mk | 1 +
android/Makefile.am | 1 +
android/avrcp-lib.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++
android/avrcp-lib.h | 34 +++++++++++++++++++++++
android/avrcp.c | 60 ++++++----------------------------------
5 files changed, 125 insertions(+), 51 deletions(-)
create mode 100644 android/avrcp-lib.c
create mode 100644 android/avrcp-lib.h
diff --git a/android/Android.mk b/android/Android.mk
index 20105e6..9b10cfe 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \
bluez/android/avdtp.c \
bluez/android/a2dp.c \
bluez/android/avctp.c \
+ bluez/android/avrcp-lib.c \
bluez/android/avrcp.c \
bluez/android/pan.c \
bluez/android/handsfree.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index 5baa8db..3032940 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -36,6 +36,7 @@ android_bluetoothd_SOURCES = android/main.c \
android/avdtp.h android/avdtp.c \
android/a2dp.h android/a2dp.c \
android/avctp.h android/avctp.c \
+ android/avrcp-lib.h android/avrcp-lib.c \
android/avrcp.h android/avrcp.c \
android/socket.h android/socket.c \
android/pan.h android/pan.c \
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
new file mode 100644
index 0000000..6dcc8ac
--- /dev/null
+++ b/android/avrcp-lib.c
@@ -0,0 +1,80 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/log.h"
+
+#include "avctp.h"
+#include "avrcp-lib.h"
+
+static GSList *devices = NULL;
+
+void avrcp_device_remove(struct avrcp_device *dev)
+{
+ devices = g_slist_remove(devices, dev);
+ avrcp_device_free(dev);
+}
+
+void avrcp_free_all(void)
+{
+ g_slist_free_full(devices, avrcp_device_free);
+ devices = NULL;
+}
+
+struct avrcp_device *avrcp_device_new(const bdaddr_t *dst)
+{
+ struct avrcp_device *dev;
+
+ dev = g_new0(struct avrcp_device, 1);
+ bacpy(&dev->dst, dst);
+ devices = g_slist_prepend(devices, dev);
+
+ return dev;
+}
+
+static int device_cmp(gconstpointer s, gconstpointer user_data)
+{
+ const struct avrcp_device *dev = s;
+ const bdaddr_t *dst = user_data;
+
+ return bacmp(&dev->dst, dst);
+}
+
+struct avrcp_device *avrcp_find(const bdaddr_t *dst)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(devices, dst, device_cmp);
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
new file mode 100644
index 0000000..bf6872e
--- /dev/null
+++ b/android/avrcp-lib.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+struct avrcp_device {
+ bdaddr_t dst;
+ struct avctp *session;
+ GIOChannel *io;
+};
+
+struct avrcp_device *avrcp_device_new(const bdaddr_t *dst);
+void avrcp_device_free(void *data);
+void avrcp_device_remove(struct avrcp_device *dev);
+void avrcp_free_all(void);
+struct avrcp_device *avrcp_find(const bdaddr_t *dst);
diff --git a/android/avrcp.c b/android/avrcp.c
index 7ee5a8a..22f0a04 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -38,6 +38,7 @@
#include "hal-msg.h"
#include "ipc.h"
#include "avctp.h"
+#include "avrcp-lib.h"
#define L2CAP_PSM_AVCTP 0x17
@@ -48,15 +49,8 @@
static bdaddr_t adapter_addr;
static uint32_t record_id = 0;
-static GSList *devices = NULL;
static GIOChannel *server = NULL;
-struct avrcp_device {
- bdaddr_t dst;
- struct avctp *session;
- GIOChannel *io;
-};
-
static const struct ipc_handler cmd_handlers[] = {
};
@@ -128,7 +122,7 @@ static sdp_record_t *avrcp_record(void)
return record;
}
-static void avrcp_device_free(void *data)
+void avrcp_device_free(void *data)
{
struct avrcp_device *dev = data;
@@ -143,31 +137,6 @@ static void avrcp_device_free(void *data)
g_free(dev);
}
-static void avrcp_device_remove(struct avrcp_device *dev)
-{
- devices = g_slist_remove(devices, dev);
- avrcp_device_free(dev);
-}
-
-static struct avrcp_device *avrcp_device_new(const bdaddr_t *dst)
-{
- struct avrcp_device *dev;
-
- dev = g_new0(struct avrcp_device, 1);
- bacpy(&dev->dst, dst);
- devices = g_slist_prepend(devices, dev);
-
- return dev;
-}
-
-static int device_cmp(gconstpointer s, gconstpointer user_data)
-{
- const struct avrcp_device *dev = s;
- const bdaddr_t *dst = user_data;
-
- return bacmp(&dev->dst, dst);
-}
-
static void disconnect_cb(void *data)
{
struct avrcp_device *dev = data;
@@ -186,7 +155,6 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
char address[18];
uint16_t imtu, omtu;
GError *gerr = NULL;
- GSList *l;
int fd;
if (err) {
@@ -209,13 +177,9 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
ba2str(&dst, address);
- l = g_slist_find_custom(devices, &dst, device_cmp);
- if (l) {
- dev = l->data;
- if (dev->session) {
- error("Unexpected connection");
- return;
- }
+ if (avrcp_find(&dst)) {
+ error("Unexpected connection");
+ return;
} else {
DBG("Incoming connection from %s", address);
dev = avrcp_device_new(&dst);
@@ -293,8 +257,7 @@ void bt_avrcp_unregister(void)
{
DBG("");
- g_slist_free_full(devices, avrcp_device_free);
- devices = NULL;
+ avrcp_free_all();
ipc_unregister(HAL_SERVICE_ID_AVRCP);
@@ -331,12 +294,10 @@ void bt_avrcp_connect(const bdaddr_t *dst)
{
struct avrcp_device *dev;
char addr[18];
- GSList *l;
DBG("");
- l = g_slist_find_custom(devices, dst, device_cmp);
- if (l)
+ if (avrcp_find(dst))
return;
dev = avrcp_device_new(dst);
@@ -352,16 +313,13 @@ void bt_avrcp_connect(const bdaddr_t *dst)
void bt_avrcp_disconnect(const bdaddr_t *dst)
{
struct avrcp_device *dev;
- GSList *l;
DBG("");
- l = g_slist_find_custom(devices, dst, device_cmp);
- if (!l)
+ dev = avrcp_find(dst);
+ if (!dev)
return;
- dev = l->data;
-
if (dev->session) {
avctp_shutdown(dev->session);
return;
--
1.8.3.2
^ permalink raw reply related
* Re: [RFC v8 06/10] Bluetooth: Introduce LE auto connection infrastructure
From: Vinicius Costa Gomes @ 2014-02-06 16:02 UTC (permalink / raw)
To: Andre Guedes; +Cc: linux-bluetooth
In-Reply-To: <1391639006-26311-6-git-send-email-andre.guedes@openbossa.org>
Hi Andre,
On 19:23 Wed 05 Feb, Andre Guedes wrote:
> This patch introduces the LE auto connection infrastructure which
> will be used to implement the LE auto connection options.
>
> In summary, the auto connection mechanism works as follows: Once the
> first pending LE connection is created, the background scanning is
> started. When the target device is found in range, the kernel
> autonomously starts the connection attempt. If connection is
> established successfully, that pending LE connection is deleted and
> the background is stopped.
>
> To achieve that, this patch introduces the hci_update_background_scan()
> which controls the background scanning state. This function starts or
> stops the background scanning based on the hdev->pend_le_conns list. If
> there is no pending LE connection, the background scanning is stopped.
> Otherwise, we start the background scanning.
>
> Then, every time a pending LE connection is added we call hci_update_
> background_scan() so the background scanning is started (in case it is
> not already running). Likewise, every time a pending LE connection is
> deleted we call hci_update_background_scan() so the background scanning
> is stopped (in case this was the last pending LE connection) or it is
> started again (in case we have more pending LE connections). Finally,
> we also call hci_update_background_scan() in hci_le_conn_failed() so
> the background scan is restarted in case the connection establishment
> fails. This way the background scanning keeps running until all pending
> LE connection are established.
>
> Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
> ---
[snip]
> static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
> {
> u8 num_reports = skb->data[0];
> void *ptr = &skb->data[1];
> s8 rssi;
>
> + hci_dev_lock(hdev);
> +
> while (num_reports--) {
> struct hci_ev_le_advertising_info *ev = ptr;
>
> + check_pending_le_conn(hdev, &ev->bdaddr, ev->bdaddr_type);
> +
Shouldn't the event type be checked to see if it is a connectable event?
> rssi = ev->data[ev->length];
> mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
> NULL, rssi, 0, 1, ev->data, ev->length);
>
> ptr += sizeof(*ev) + ev->length + 1;
> }
> +
> + hci_dev_unlock(hdev);
> }
>
> static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
> --
> 1.8.5.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Cheers,
--
Vinicius
^ permalink raw reply
* [PATCH v3 8/8] android/pan: Bring bridge interface down before removing it
From: Szymon Janc @ 2014-02-06 15:28 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391700522-9036-1-git-send-email-szymon.janc@tieto.com>
Otherwise bridge will be 'in use' and won't be removed.
---
android/pan.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/android/pan.c b/android/pan.c
index 418e2a4..bcbb3d8 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -132,6 +132,31 @@ static int nap_create_bridge(void)
return err;
}
+static int bridge_if_down(void)
+{
+ struct ifreq ifr;
+ int sk, err;
+
+ sk = socket(AF_INET, SOCK_DGRAM, 0);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, BNEP_BRIDGE, IF_NAMESIZE - 1);
+
+ ifr.ifr_flags &= ~IFF_UP;
+
+ /* Bring down the interface */
+ err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
+
+ close(sk);
+
+ if (err < 0) {
+ error("pan: Could not bring down %s", BNEP_BRIDGE);
+ return err;
+ }
+
+ return 0;
+}
+
static int nap_remove_bridge(void)
{
int sk, err;
@@ -141,6 +166,8 @@ static int nap_remove_bridge(void)
if (!nap_dev.bridge)
return 0;
+ bridge_if_down();
+
sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -EOPNOTSUPP;
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 7/8] android/pan: Pass error in nap_remove_bridge
From: Szymon Janc @ 2014-02-06 15:28 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391700522-9036-1-git-send-email-szymon.janc@tieto.com>
Don't return EOPNOTSUPP but just pass error from errno.
---
android/pan.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/android/pan.c b/android/pan.c
index 1cb82a1..418e2a4 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -146,10 +146,13 @@ static int nap_remove_bridge(void)
return -EOPNOTSUPP;
err = ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+ if (err < 0)
+ err = -errno;
+
close(sk);
if (err < 0)
- return -EOPNOTSUPP;
+ return err;
nap_dev.bridge = false;
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 6/8] android/pan: Use ioctl instead of sysfs for setting forward delay
From: Szymon Janc @ 2014-02-06 15:28 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391700522-9036-1-git-send-email-szymon.janc@tieto.com>
Using sysfs is causing problems due to filesystem permissions
(bluetoothd is running as bluetooth user) and bluetoothd already has
required capabilities for setting forward delay through ioctl.
---
android/pan.c | 31 +++++++++++++++----------------
1 file changed, 15 insertions(+), 16 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 83def53..1cb82a1 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -33,6 +33,9 @@
#include <sys/wait.h>
#include <net/if.h>
#include <linux/sockios.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <linux/if_bridge.h>
#include "btio/btio.h"
#include "lib/bluetooth.h"
@@ -54,7 +57,6 @@
#define BNEP_BRIDGE "bt-pan"
#define BNEP_PANU_INTERFACE "bt-pan"
#define BNEP_NAP_INTERFACE "bt-pan%d"
-#define FORWARD_DELAY_PATH "/sys/class/net/"BNEP_BRIDGE"/bridge/forward_delay"
static bdaddr_t adapter_addr;
GSList *devices = NULL;
@@ -80,25 +82,22 @@ static struct {
.bridge = false,
};
-
-static int set_forward_delay(void)
+static int set_forward_delay(int sk)
{
- int fd, ret;
-
- fd = open(FORWARD_DELAY_PATH, O_RDWR);
- if (fd < 0) {
- int err = -errno;
+ unsigned long args[4] = { BRCTL_SET_BRIDGE_FORWARD_DELAY, 0 ,0, 0 };
+ struct ifreq ifr;
- error("pan: open forward delay file failed: %d (%s)",
- -err, strerror(-err));
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, BNEP_BRIDGE, IFNAMSIZ);
+ ifr.ifr_data = (char *) args;
- return err;
+ if (ioctl(sk, SIOCDEVPRIVATE, &ifr) < 0) {
+ error("pan: setting forward delay failed: %d (%s)",
+ errno, strerror(errno));
+ return -1;
}
- ret = write(fd, "0", sizeof("0"));
- close(fd);
-
- return ret;
+ return 0;
}
static int nap_create_bridge(void)
@@ -122,7 +121,7 @@ static int nap_create_bridge(void)
}
}
- err = set_forward_delay();
+ err = set_forward_delay(sk);
if (err < 0)
ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 5/8] android/pan: Fix bnep interface name
From: Szymon Janc @ 2014-02-06 15:28 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1391700522-9036-1-git-send-email-szymon.janc@tieto.com>
From: Ravi kumar Veeramally <ravikumar.veeramally@linux.intel.com>
Android uses bt-pan static interface in PAN profile. In server role
it uses it as bridge name. But current implementaion passes interface
names like bnep0, bnep1... Android Framework is unaware of this name
and unable to allocate IP address after profile connection setup.
---
android/pan.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 0d6adaf..83def53 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -51,8 +51,9 @@
#define SVC_HINT_NETWORKING 0x02
-#define BNEP_BRIDGE "bnep"
+#define BNEP_BRIDGE "bt-pan"
#define BNEP_PANU_INTERFACE "bt-pan"
+#define BNEP_NAP_INTERFACE "bt-pan%d"
#define FORWARD_DELAY_PATH "/sys/class/net/"BNEP_BRIDGE"/bridge/forward_delay"
static bdaddr_t adapter_addr;
@@ -229,8 +230,13 @@ static void bt_pan_notify_ctrl_state(struct pan_device *dev, uint8_t state)
ev.state = state;
ev.local_role = local_role;
ev.status = HAL_STATUS_SUCCESS;
+
memset(ev.name, 0, sizeof(ev.name));
- memcpy(ev.name, dev->iface, sizeof(dev->iface));
+
+ if (local_role == HAL_PAN_ROLE_NAP)
+ memcpy(ev.name, BNEP_BRIDGE, sizeof(BNEP_BRIDGE));
+ else
+ memcpy(ev.name, dev->iface, sizeof(dev->iface));
ipc_send_notif(HAL_SERVICE_ID_PAN, HAL_EV_PAN_CTRL_STATE, sizeof(ev),
&ev);
@@ -542,6 +548,9 @@ static void nap_confirm_cb(GIOChannel *chan, gpointer data)
local_role = HAL_PAN_ROLE_NAP;
dev->role = HAL_PAN_ROLE_PANU;
+ strncpy(dev->iface, BNEP_NAP_INTERFACE, 16);
+ dev->iface[15] = '\0';
+
dev->io = g_io_channel_ref(chan);
g_io_channel_set_close_on_unref(dev->io, TRUE);
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 4/8] android/pan: Fix unregistering NAP bridge
From: Szymon Janc @ 2014-02-06 15:28 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391700522-9036-1-git-send-email-szymon.janc@tieto.com>
This fix not removing NAP bridge in case of error or last device
disconnect.
---
android/pan.c | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index d010e09..0d6adaf 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -72,11 +72,14 @@ struct pan_device {
static struct {
uint32_t record_id;
GIOChannel *io;
+ bool bridge;
} nap_dev = {
.record_id = 0,
.io = NULL,
+ .bridge = false,
};
+
static int set_forward_delay(void)
{
int fd, ret;
@@ -103,6 +106,9 @@ static int nap_create_bridge(void)
DBG("%s", BNEP_BRIDGE);
+ if (nap_dev.bridge)
+ return 0;
+
sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -EOPNOTSUPP;
@@ -121,6 +127,8 @@ static int nap_create_bridge(void)
close(sk);
+ nap_dev.bridge = err == 0;
+
return err;
}
@@ -130,6 +138,9 @@ static int nap_remove_bridge(void)
DBG("%s", BNEP_BRIDGE);
+ if (!nap_dev.bridge)
+ return 0;
+
sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sk < 0)
return -EOPNOTSUPP;
@@ -140,6 +151,8 @@ static int nap_remove_bridge(void)
if (err < 0)
return -EOPNOTSUPP;
+ nap_dev.bridge = false;
+
return 0;
}
@@ -175,8 +188,10 @@ static void pan_device_remove(struct pan_device *dev)
{
devices = g_slist_remove(devices, dev);
- if (g_slist_length(devices) == 0)
+ if (g_slist_length(devices) == 0) {
local_role = HAL_PAN_ROLE_NONE;
+ nap_remove_bridge();
+ }
pan_device_free(dev);
}
@@ -455,8 +470,12 @@ static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
goto failed;
}
+ if (nap_create_bridge() < 0)
+ goto failed;
+
if (bnep_server_add(sk, dst_role, BNEP_BRIDGE, dev->iface,
&dev->dst) < 0) {
+ nap_remove_bridge();
error("server_connadd failed");
rsp = BNEP_CONN_NOT_ALLOWED;
goto failed;
@@ -557,14 +576,9 @@ static void destroy_nap_device(void)
static int register_nap_server(void)
{
GError *gerr = NULL;
- int err;
DBG("");
- err = nap_create_bridge();
- if (err < 0)
- return err;
-
nap_dev.io = bt_io_listen(NULL, nap_confirm_cb, NULL, NULL, &gerr,
BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
BT_IO_OPT_PSM, BNEP_PSM,
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 3/8] android/pan: Move functions up to avoid forward declarations
From: Szymon Janc @ 2014-02-06 15:28 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391700522-9036-1-git-send-email-szymon.janc@tieto.com>
---
android/pan.c | 132 +++++++++++++++++++++++++++++-----------------------------
1 file changed, 66 insertions(+), 66 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index b8d7404..d010e09 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -77,6 +77,72 @@ static struct {
.io = NULL,
};
+static int set_forward_delay(void)
+{
+ int fd, ret;
+
+ fd = open(FORWARD_DELAY_PATH, O_RDWR);
+ if (fd < 0) {
+ int err = -errno;
+
+ error("pan: open forward delay file failed: %d (%s)",
+ -err, strerror(-err));
+
+ return err;
+ }
+
+ ret = write(fd, "0", sizeof("0"));
+ close(fd);
+
+ return ret;
+}
+
+static int nap_create_bridge(void)
+{
+ int sk, err;
+
+ DBG("%s", BNEP_BRIDGE);
+
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -EOPNOTSUPP;
+
+ if (ioctl(sk, SIOCBRADDBR, BNEP_BRIDGE) < 0) {
+ err = -errno;
+ if (err != -EEXIST) {
+ close(sk);
+ return -EOPNOTSUPP;
+ }
+ }
+
+ err = set_forward_delay();
+ if (err < 0)
+ ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+
+ close(sk);
+
+ return err;
+}
+
+static int nap_remove_bridge(void)
+{
+ int sk, err;
+
+ DBG("%s", BNEP_BRIDGE);
+
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -EOPNOTSUPP;
+
+ err = ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+ close(sk);
+
+ if (err < 0)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
static int device_cmp(gconstpointer s, gconstpointer user_data)
{
const struct pan_device *dev = s;
@@ -475,72 +541,6 @@ failed:
bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
}
-static int set_forward_delay(void)
-{
- int fd, ret;
-
- fd = open(FORWARD_DELAY_PATH, O_RDWR);
- if (fd < 0) {
- int err = -errno;
-
- error("pan: open forward delay file failed: %d (%s)",
- -err, strerror(-err));
-
- return err;
- }
-
- ret = write(fd, "0", sizeof("0"));
- close(fd);
-
- return ret;
-}
-
-static int nap_create_bridge(void)
-{
- int sk, err;
-
- DBG("%s", BNEP_BRIDGE);
-
- sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (sk < 0)
- return -EOPNOTSUPP;
-
- if (ioctl(sk, SIOCBRADDBR, BNEP_BRIDGE) < 0) {
- err = -errno;
- if (err != -EEXIST) {
- close(sk);
- return -EOPNOTSUPP;
- }
- }
-
- err = set_forward_delay();
- if (err < 0)
- ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
-
- close(sk);
-
- return err;
-}
-
-static int nap_remove_bridge(void)
-{
- int sk, err;
-
- DBG("%s", BNEP_BRIDGE);
-
- sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (sk < 0)
- return -EOPNOTSUPP;
-
- err = ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
- close(sk);
-
- if (err < 0)
- return -EOPNOTSUPP;
-
- return 0;
-}
-
static void destroy_nap_device(void)
{
DBG("");
--
1.8.3.2
^ permalink raw reply related
* [PATCH v3 2/8] profiles/network: Allow to pass interface name to bnep_new
From: Szymon Janc @ 2014-02-06 15:28 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1391700522-9036-1-git-send-email-szymon.janc@tieto.com>
---
android/pan.c | 3 ++-
profiles/network/bnep.c | 5 ++++-
profiles/network/bnep.h | 3 ++-
profiles/network/connection.c | 6 ++++--
4 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 6b19120..b8d7404 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -52,6 +52,7 @@
#define SVC_HINT_NETWORKING 0x02
#define BNEP_BRIDGE "bnep"
+#define BNEP_PANU_INTERFACE "bt-pan"
#define FORWARD_DELAY_PATH "/sys/class/net/"BNEP_BRIDGE"/bridge/forward_delay"
static bdaddr_t adapter_addr;
@@ -202,7 +203,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
sk = g_io_channel_unix_get_fd(dev->io);
- dev->session = bnep_new(sk, l_role, r_role);
+ dev->session = bnep_new(sk, l_role, r_role, BNEP_PANU_INTERFACE);
if (!dev->session)
goto fail;
diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index 82d0d99..1aa0783 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -386,7 +386,8 @@ static gboolean bnep_conn_req_to(gpointer user_data)
return FALSE;
}
-struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role)
+struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role,
+ char *iface)
{
struct bnep *session;
int dup_fd;
@@ -399,6 +400,8 @@ struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role)
session->io = g_io_channel_unix_new(dup_fd);
session->src = local_role;
session->dst = remote_role;
+ strncpy(session->iface, iface, 16);
+ session->iface[15] = '\0';
g_io_channel_set_close_on_unref(session->io, TRUE);
session->watch = g_io_add_watch(session->io,
diff --git a/profiles/network/bnep.h b/profiles/network/bnep.h
index 87cdacf..bc43d4f 100644
--- a/profiles/network/bnep.h
+++ b/profiles/network/bnep.h
@@ -30,7 +30,8 @@ uint16_t bnep_service_id(const char *svc);
const char *bnep_uuid(uint16_t id);
const char *bnep_name(uint16_t id);
-struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role);
+struct bnep *bnep_new(int sk, uint16_t local_role, uint16_t remote_role,
+ char *iface);
void bnep_free(struct bnep *session);
typedef void (*bnep_connect_cb) (char *iface, int err, void *data);
diff --git a/profiles/network/connection.c b/profiles/network/connection.c
index 5f45fdb..cc73989 100644
--- a/profiles/network/connection.c
+++ b/profiles/network/connection.c
@@ -51,6 +51,7 @@
#include "connection.h"
#define NETWORK_PEER_INTERFACE "org.bluez.Network1"
+#define BNEP_INTERFACE "bnep%d"
typedef enum {
CONNECTED,
@@ -128,7 +129,8 @@ static void bnep_disconn_cb(gpointer data)
nc->state = DISCONNECTED;
memset(nc->dev, 0, sizeof(nc->dev));
- strcpy(nc->dev, "bnep%d");
+ strncpy(nc->dev, BNEP_INTERFACE, 16);
+ nc->dev[15] = '\0';
bnep_free(nc->session);
nc->session = NULL;
@@ -243,7 +245,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
}
sk = g_io_channel_unix_get_fd(nc->io);
- nc->session = bnep_new(sk, BNEP_SVC_PANU, nc->id);
+ nc->session = bnep_new(sk, BNEP_SVC_PANU, nc->id, BNEP_INTERFACE);
if (!nc->session)
goto failed;
--
1.8.3.2
^ 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