Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [RFC v2 01/15] Bluetooth: Refactor hci_disconn_complete_evt
From: Marcel Holtmann @ 2013-10-29 22:52 UTC (permalink / raw)
  To: Andre Guedes; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1383053160-10175-2-git-send-email-andre.guedes@openbossa.org>

Hi Andre,

> hci_disconn_complete_evt() logic is more complicated than what it
> should be, making it hard to follow and add new features.
> 
> So this patch does some code refactoring by handling the error cases
> in the beginning of the function and by moving the main flow into the
> first level of function scope. No change is done in the event handling
> logic itself.
> 
> Besides organizing this messy code, this patch makes easier to add
> code for handling LE auto connection (which will be added in a further
> patch).
> 
> Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
> ---
> net/bluetooth/hci_event.c | 62 +++++++++++++++++++++++++----------------------
> 1 file changed, 33 insertions(+), 29 deletions(-)
> 
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 5935f74..8b7cd37 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -1783,6 +1783,8 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> {
> 	struct hci_ev_disconn_complete *ev = (void *) skb->data;
> 	struct hci_conn *conn;
> +	u8 type;
> +	bool send_mgmt_event = false;
> 
> 	BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
> 
> @@ -1792,44 +1794,46 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> 	if (!conn)
> 		goto unlock;
> 
> -	if (ev->status == 0)
> -		conn->state = BT_CLOSED;
> -
> 	if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
> -	    (conn->type == ACL_LINK || conn->type == LE_LINK)) {
> -		if (ev->status) {
> +	    (conn->type == ACL_LINK || conn->type == LE_LINK))
> +		send_mgmt_event = true;
> +
> +	if (ev->status) {
> +		if (send_mgmt_event)
> 			mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
> 					       conn->dst_type, ev->status);
> -		} else {
> -			u8 reason = hci_to_mgmt_reason(ev->reason);
> -
> -			mgmt_device_disconnected(hdev, &conn->dst, conn->type,
> -						 conn->dst_type, reason);
> -		}
> +		return;
> 	}

so I get the feeling that mgmt_disconnect_failed should check the link type all by itself. Since we are handing it over to the function anyway. And then this send_mgmt_event could be just removed.

> -	if (ev->status == 0) {
> -		u8 type = conn->type;
> +	conn->state = BT_CLOSED;
> 
> -		if (type == ACL_LINK && conn->flush_key)
> -			hci_remove_link_key(hdev, &conn->dst);
> -		hci_proto_disconn_cfm(conn, ev->reason);
> -		hci_conn_del(conn);
> +	if (send_mgmt_event) {
> +		u8 reason = hci_to_mgmt_reason(ev->reason);
> 
> -		/* Re-enable advertising if necessary, since it might
> -		 * have been disabled by the connection. From the
> -		 * HCI_LE_Set_Advertise_Enable command description in
> -		 * the core specification (v4.0):
> -		 * "The Controller shall continue advertising until the Host
> -		 * issues an LE_Set_Advertise_Enable command with
> -		 * Advertising_Enable set to 0x00 (Advertising is disabled)
> -		 * or until a connection is created or until the Advertising
> -		 * is timed out due to Directed Advertising."
> -		 */
> -		if (type == LE_LINK)
> -			mgmt_reenable_advertising(hdev);
> +		mgmt_device_disconnected(hdev, &conn->dst, conn->type,
> +					 conn->dst_type, reason);
> 	}

Same here. Just make sure that mgmt_device_disconneted checks the link type by itself and call it unconditional.

> 
> +	if (conn->type == ACL_LINK && conn->flush_key)
> +		hci_remove_link_key(hdev, &conn->dst);
> +
> +	type = conn->type;
> +	hci_proto_disconn_cfm(conn, ev->reason);
> +	hci_conn_del(conn);
> +
> +	/* Re-enable advertising if necessary, since it might
> +	 * have been disabled by the connection. From the
> +	 * HCI_LE_Set_Advertise_Enable command description in
> +	 * the core specification (v4.0):
> +	 * "The Controller shall continue advertising until the Host
> +	 * issues an LE_Set_Advertise_Enable command with
> +	 * Advertising_Enable set to 0x00 (Advertising is disabled)
> +	 * or until a connection is created or until the Advertising
> +	 * is timed out due to Directed Advertising."
> +	 */
> +	if (type == LE_LINK)
> +		mgmt_reenable_advertising(hdev);
> +
> unlock:
> 	hci_dev_unlock(hdev);
> }

Regards

Marcel


^ permalink raw reply

* RE: l2cap sockets not properly multiplexed on ARM
From: Tim Tisdall @ 2013-10-29 20:44 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org

on IRC:
<lizardo> dack: it would be nice if you could provide a sample C code that shows the issue you described on the mailing list
<lizardo> specially the arguments you are using for bind/connect/setsockopt/listen/*   (I'm assuming you are using sockets directly)
<dack> lizardo:  unfortunately my code is a mess of C mixed with Python.   yeah, I could provide the argument details



HCI sockets
-----------

socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)
bind(device_id)  // I get device_id's from udev
hci_le_set_scan_parameters(fd, 0, 0x10, 0x10, 0, 0, 1000)  // bluez method in the shared library
setsockopt(SOL_HCI, HCI_FILTER, hci_filter) // I set the filter to let everything through (for testing)
hci_le_set_scan_enable(fd, 1, 0, 1000)  // bluez method in the shared library to turn on scanning
// I shut blocking off on the socket
// I then use epoll to wait for events

L2CAP sockets
-------------

socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)
bind(bdaddr, 0)  // bind to bluetooth address and PSM 0 (Python doesn't support LE directly,
                 // but this is enough for binding to the right device
// shut blocking off

// next part I do in C because of the lack of support in Python...
    PySocketSockObject *sock;  // the socket I created in Python
    char *bdaddr;
    int cid = 0;
    int psm = 0;
    int bdaddr_type = BDADDR_LE_PUBLIC;
    int err;
    struct sockaddr_l2 addr;
       

    // code here to set &bdaddr, &cid, &psm, &bdaddr_type
    // from arguments passed from Python or they're
    // left to their defaults

       
    memset(&addr, 0, sizeof(addr));
    addr.l2_family = sock->sock_family;
    str2ba(bdaddr, &addr.l2_bdaddr);
    
    if (cid)
            addr.l2_cid = htobs(cid);
    else
            addr.l2_psm = htobs(psm);
   
    addr.l2_bdaddr_type = bdaddr_type;
   
   
    err = connect(sock->sock_fd, (struct sockaddr *) &addr, sizeof(addr));

// lastly use epoll to wait for events


I then set CCC values on some attributes to get notifications of changes to sensor readings


Results
-------

On my x86 tests:  everything works fine, notifications come down the proper L2CAP sockets
on my ARM tests:  all notifications come down whatever L2CAP socket was established last


I just realized I missed some fundamental details in the previous emails...

bluez 4.101
linux kernel 3.4.43 compiled with ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf on Allwinner A10 chipset
tried on various armhf chipsets with the same results using kernel 3.0.X

^ permalink raw reply

* [PATCH] Bluetooth: Set default own address type only during controller setup
From: Marcel Holtmann @ 2013-10-29 19:26 UTC (permalink / raw)
  To: linux-bluetooth

The default own address type is currently set at every power on of
a controller. This overwrites the value set via debugfs. To avoid
this issue, set the default own address type only during controller
setup.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/hci_core.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 6ccc4eb..03e8355 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1275,15 +1275,17 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
 		hci_setup_link_policy(req);
 
 	if (lmp_le_capable(hdev)) {
-		/* If the controller has a public BD_ADDR, then by
-		 * default use that one. If this is a LE only
-		 * controller without one, default to the random
-		 * address.
-		 */
-		if (bacmp(&hdev->bdaddr, BDADDR_ANY))
-			hdev->own_addr_type = ADDR_LE_DEV_PUBLIC;
-		else
-			hdev->own_addr_type = ADDR_LE_DEV_RANDOM;
+		if (test_bit(HCI_SETUP, &hdev->dev_flags)) {
+			/* If the controller has a public BD_ADDR, then
+			 * by default use that one. If this is a LE only
+			 * controller without a public address, default
+			 * to the random address.
+			 */
+			if (bacmp(&hdev->bdaddr, BDADDR_ANY))
+				hdev->own_addr_type = ADDR_LE_DEV_PUBLIC;
+			else
+				hdev->own_addr_type = ADDR_LE_DEV_RANDOM;
+		}
 
 		hci_set_le_support(req);
 	}
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH 2/2] android: Suppress compiler warnings not used in autotools build
From: Szymon Janc @ 2013-10-29 15:23 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1383060218-25693-1-git-send-email-szymon.janc@tieto.com>

Android build system is enabling some additional warnings that are not
enabled when building with autotools. This avoids spurious warnings
while building on Android.
---
 android/Android.mk | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/android/Android.mk b/android/Android.mk
index c88b27e..fc1b276 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -9,6 +9,9 @@ pathmap_INCL += glib:external/bluetooth/glib
 # Specify common compiler flags
 BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
 
+# Disable warnings enabled by Android but not enabled in autotools build
+BLUEZ_COMMON_CFLAGS += -Wno-pointer-arith
+
 #
 # Android BlueZ daemon (bluetoothd)
 #
-- 
1.8.4.1


^ permalink raw reply related

* [PATCH 1/2] android: Add common place for adding compiler flags in Android.mk
From: Szymon Janc @ 2013-10-29 15:23 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This will contain CFLAGS common for all BlueZ code.
---
 android/Android.mk | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/android/Android.mk b/android/Android.mk
index d8f9d0d..c88b27e 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -6,6 +6,9 @@ BLUEZ_VERSION := $(shell grep ^AC_INIT $(LOCAL_PATH)/../configure.ac | cpp -P -D
 # Specify pathmap for glib
 pathmap_INCL += glib:external/bluetooth/glib
 
+# Specify common compiler flags
+BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
+
 #
 # Android BlueZ daemon (bluetoothd)
 #
@@ -39,7 +42,7 @@ LOCAL_C_INCLUDES += \
 	$(LOCAL_PATH)/../src \
 	$(LOCAL_PATH)/../lib \
 
-LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\" \
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) \
 	-DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
 
 LOCAL_SHARED_LIBRARIES := \
@@ -84,6 +87,8 @@ LOCAL_C_INCLUDES += \
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) \
+
 LOCAL_MODULE := bluetooth.default
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
 LOCAL_MODULE_TAGS := optional
@@ -112,7 +117,7 @@ LOCAL_SRC_FILES := \
 	client/if-pan.c \
 	client/if-sock.c \
 
-LOCAL_CFLAGS := -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
 
 LOCAL_SHARED_LIBRARIES := libhardware
 
-- 
1.8.4.1


^ permalink raw reply related

* [PATCH BlueZ] audio/AVRCP: Always assign a player to TG role
From: Luiz Augusto von Dentz @ 2013-10-29 14:07 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Currently the code does not assign a player if version is bellow 1.3,
but sometimes the version may not be initialized correctly e.g: record
could not be fetch.

Futhermore by assigning a player for 1.0 CT it won't break backward
compatibility as no commands will be sent but adds the possibility to
respond properly in case the CT is sending commands above its own
version which is a violation of the spec but unfortunately there exists
such stacks on the market.
---
 profiles/audio/avrcp.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 296067c..cd027c6 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -3363,9 +3363,6 @@ static void target_init(struct avrcp *session)
 	if (service != NULL)
 		btd_service_connecting_complete(service, 0);
 
-	if (target->version < 0x0103)
-		return;
-
 	player = g_slist_nth_data(server->players, 0);
 	if (player != NULL) {
 		target->player = player;
-- 
1.8.3.1


^ permalink raw reply related

* l2cap sockets not properly multiplexed on ARM
From: Tim Tisdall @ 2013-10-29 13:43 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org

[-- Attachment #1: Type: text/plain, Size: 2988 bytes --]

I was talking to Marcel on the freenode chat and he suggested I post this issue to the mailing list...

I have some code where I make LE L2CAP connections to multiple sensor devices.  On my laptop and any other x86-like device I have no problems with the code and everything works correctly.  When I try to run the same code on several different ARM machines I have the same problem where the L2CAP sockets seem to get merged and all data returns on the last connected one.

Marcel asked for me to post the btmon logs of my problem but the logs essentially show that things are working correctly because I think it's getting all the data on the HCI level.  You can see the 2 sensors have connection handles 64 and 65.  However here is some output from my code (it's all coming down one file descriptor corresponding to the "78:c5:e5:6c:47:d3" device and the earlier file descriptor now receives nothing):

2013-10-28 20:18:54+0000 [-] 78:c5:e5:6c:47:d3 x-axis: -1
2013-10-28 20:18:54+0000 [-] 78:c5:e5:6c:47:d3 y-axis: -9
2013-10-28 20:18:54+0000 [-] 78:c5:e5:6c:47:d3 z-axis: -64
2013-10-28 20:18:54+0000 [-] 78:c5:e5:6c:47:d3 x-axis: -7
2013-10-28 20:18:54+0000 [-] 78:c5:e5:6c:47:d3 y-axis: -51
2013-10-28 20:18:54+0000 [-] 78:c5:e5:6c:47:d3 x-axis: 2
2013-10-28 20:18:54+0000 [-] 78:c5:e5:6c:47:d3 y-axis: -8
2013-10-28 20:19:10+0000 [-] 78:c5:e5:6c:47:d3 x-axis: -7
2013-10-28 20:19:10+0000 [-] 78:c5:e5:6c:47:d3 x-axis: -1

which corresponds to the btmon output:
[hci0] 20:18:54.359162 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 ff                          .....*..        
[hci0] 20:18:54.359454 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 f7                          ........        
[hci0] 20:18:54.360633 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 32 00 c0                          .....2..        
[hci0] 20:18:54.561663 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 f9                          .....*..        
[hci0] 20:18:54.564898 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 cd                          ........        
[hci0] 20:18:54.696646 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 02                          .....*..        
[hci0] 20:18:54.698873 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 f8                          ........        
[hci0] 20:19:10.383417 > ACL Data: handle 65 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 f9                          .....*..        
[hci0] 20:19:10.439511 > ACL Data: handle 65 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 ff                          .....*..        


The ATT_OP_WRITE_CMD command to get the notifications are sent down the L2CAP sockets so communication towards the sensors seems to work correctly, it's just the data coming the other way is the issue.

-Tim

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: btmon.log --]
[-- Type: text/x-log; name="btmon.log", Size: 16650 bytes --]

Bluetooth monitor ver 4.101
[hci0] 20:18:14.338542 = New Index: 00:02:72:3E:7F:9B (BR/EDR,USB,hci0)
[hci0] 20:18:25.230025 < HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7
            00 10 00 10 00 00 00                             .......         
[hci0] 20:18:25.230989 > HCI Event: Command Complete (0x0e) plen 4
            01 0b 20 00                                      .. .            
[hci0] 20:18:25.231782 < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2
            01 00                                            ..              
[hci0] 20:18:25.232986 > HCI Event: Command Complete (0x0e) plen 4
            01 0c 20 00                                      .. .            
{hci0} 20:18:25.233050 @ Discovering: 0x01 (0)
[hci0] 20:18:37.428871 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 a2 47 6c e5 c5 78 03 02 01 05 a6     .....Gl..x..... 
{hci0} 20:18:37.429647 @ Device Found: 78:C5:E5:6C:47:A2 (1) rssi -90 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:37.637286 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 a2 47 6c e5 c5 78 03 02 01 05 a4     .....Gl..x..... 
{hci0} 20:18:37.638128 @ Device Found: 78:C5:E5:6C:47:A2 (1) rssi -92 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:37.661732 < HCI Command: LE Create Connection (0x08|0x000d) plen 25
            60 00 30 00 00 00 a2 47 6c e5 c5 78 00 28 00 38  `.0....Gl..x.(.8
            00 00 00 2a 00 00 00 00 00                       ...*.....       
[hci0] 20:18:37.663267 > HCI Event: Command Status (0x0f) plen 4
            00 01 0d 20                                      ...             
[hci0] 20:18:37.743164 > HCI Event: LE Meta Event (0x3e) plen 19
            01 00 40 00 00 00 a2 47 6c e5 c5 78 36 00 00 00  ..@....Gl..x6...
            2a 00 05                                         *..             
{hci0} 20:18:37.746828 @ Device Connected: 78:C5:E5:6C:47:A2 (1) flags 0x0000
[hci0] 20:18:37.802830 < ACL Data: handle 64 flags 0x00 dlen 9
            05 00 04 00 52 2b 00 01 00                       ....R+...       
[hci0] 20:18:37.830466 < ACL Data: handle 64 flags 0x00 dlen 9
            05 00 04 00 52 33 00 01 00                       ....R3...       
[hci0] 20:18:37.831004 < ACL Data: handle 64 flags 0x00 dlen 9
            05 00 04 00 52 2f 00 01 00                       ....R/...       
[hci0] 20:18:37.831305 < ACL Data: handle 64 flags 0x00 dlen 9
            05 00 04 00 52 20 00 01 00                       ....R ...       
[hci0] 20:18:37.831434 < ACL Data: handle 64 flags 0x00 dlen 13
            09 00 04 00 0e 2a 00 32 00 2e 00 1f 00           .....*.2.....   
[hci0] 20:18:37.821898 > ACL Data: handle 64 flags 0x02 dlen 16
            0c 00 05 00 12 01 08 00 10 00 20 00 00 00 2c 01  .......... ...,.
[hci0] 20:18:37.832516 < ACL Data: handle 64 flags 0x00 dlen 10
            06 00 05 00 13 01 02 00 00 00                    ..........      
[hci0] 20:18:37.832721 < HCI Command: LE Connection Update (0x08|0x0013) plen 14
            40 00 10 00 20 00 00 00 2c 01 01 00 01 00        @... ...,.....  
[hci0] 20:18:37.865257 > HCI Event: Command Status (0x0f) plen 4
            00 01 13 20                                      ...             
[hci0] 20:18:37.889123 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 dd                          ........        
[hci0] 20:18:37.889670 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 32 00 cd                          .....2..        
[hci0] 20:18:37.957320 > HCI Event: Number of Completed Packets (0x13) plen 5
            01 40 00 02 00                                   .@...           
[hci0] 20:18:37.959205 > HCI Event: Number of Completed Packets (0x13) plen 5
            01 40 00 02 00                                   .@...           
[hci0] 20:18:38.092097 > ACL Data: handle 64 flags 0x02 dlen 9
            05 00 04 00 0f 00 cd dd 51                       ........Q       
[hci0] 20:18:38.094177 > HCI Event: Number of Completed Packets (0x13) plen 5
            01 40 00 02 00                                   .@...           
[hci0] 20:18:38.094463 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 c8                          .....*..        
[hci0] 20:18:38.094586 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 85                          ........        
[hci0] 20:18:38.159057 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 32 00 16                          .....2..        
[hci0] 20:18:38.160390 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 02                          .....*..        
[hci0] 20:18:38.160518 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 fe                          ........        
[hci0] 20:18:38.194021 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 a2 47 6c e5 c5 78 03 02 01 05 a9     .....Gl..x..... 
{hci0} 20:18:38.194736 @ Device Found: 78:C5:E5:6C:47:A2 (1) rssi -87 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:38.294342 > HCI Event: Disconn Complete (0x05) plen 4
            00 40 00 13                                      .@..            
{hci0} 20:18:38.296381 @ Device Disconnected: 78:C5:E5:6C:47:A2 (1)
[hci0] 20:18:38.299183 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 a2 47 6c e5 c5 78 03 02 01 05 ba     .....Gl..x..... 
{hci0} 20:18:38.323501 @ Device Found: 78:C5:E5:6C:47:A2 (1) rssi -70 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:38.402894 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 a2 47 6c e5 c5 78 03 02 01 05 b3     .....Gl..x..... 
{hci0} 20:18:38.403917 @ Device Found: 78:C5:E5:6C:47:A2 (1) rssi -77 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:38.465634 < HCI Command: LE Create Connection (0x08|0x000d) plen 25
            60 00 30 00 00 00 a2 47 6c e5 c5 78 00 28 00 38  `.0....Gl..x.(.8
            00 00 00 2a 00 00 00 00 00                       ...*.....       
[hci0] 20:18:38.467407 > HCI Event: Command Status (0x0f) plen 4
            00 01 0d 20                                      ...             
[hci0] 20:18:38.511164 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 a2 47 6c e5 c5 78 03 02 01 05 ba     .....Gl..x..... 
{hci0} 20:18:38.514909 @ Device Found: 78:C5:E5:6C:47:A2 (1) rssi -70 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:38.615794 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 a2 47 6c e5 c5 78 03 02 01 05 b4     .....Gl..x..... 
{hci0} 20:18:38.617512 @ Device Found: 78:C5:E5:6C:47:A2 (1) rssi -76 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:38.718783 > HCI Event: LE Meta Event (0x3e) plen 19
            01 00 40 00 00 00 a2 47 6c e5 c5 78 36 00 00 00  ..@....Gl..x6...
            2a 00 05                                         *..             
{hci0} 20:18:38.722401 @ Device Connected: 78:C5:E5:6C:47:A2 (1) flags 0x0000
[hci0] 20:18:38.766767 > ACL Data: handle 64 flags 0x02 dlen 16
            0c 00 05 00 12 02 08 00 10 00 20 00 00 00 2c 01  .......... ...,.
[hci0] 20:18:38.770494 < ACL Data: handle 64 flags 0x00 dlen 10
            06 00 05 00 13 02 02 00 00 00                    ..........      
[hci0] 20:18:38.770750 < HCI Command: LE Connection Update (0x08|0x0013) plen 14
            40 00 10 00 20 00 00 00 2c 01 01 00 01 00        @... ...,.....  
[hci0] 20:18:38.774270 > HCI Event: Command Status (0x0f) plen 4
            00 01 13 20                                      ...             
[hci0] 20:18:38.782653 < ACL Data: handle 64 flags 0x00 dlen 9
            05 00 04 00 52 2b 00 01 00                       ....R+...       
[hci0] 20:18:38.810351 < ACL Data: handle 64 flags 0x00 dlen 9
            05 00 04 00 52 33 00 01 00                       ....R3...       
[hci0] 20:18:38.813370 < ACL Data: handle 64 flags 0x00 dlen 9
            05 00 04 00 52 2f 00 01 00                       ....R/...       
[hci0] 20:18:38.815045 < ACL Data: handle 64 flags 0x00 dlen 9
            05 00 04 00 52 20 00 01 00                       ....R ...       
[hci0] 20:18:38.825889 < ACL Data: handle 64 flags 0x00 dlen 13
            09 00 04 00 0e 2a 00 32 00 2e 00 1f 00           .....*.2.....   
[hci0] 20:18:38.834141 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 f8                          ........        
[hci0] 20:18:38.834673 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 32 00 c1                          .....2..        
[hci0] 20:18:38.970272 > HCI Event: Number of Completed Packets (0x13) plen 5
            01 40 00 02 00                                   .@...           
[hci0] 20:18:38.972162 > HCI Event: Number of Completed Packets (0x13) plen 5
            01 40 00 02 00                                   .@...           
[hci0] 20:18:39.038229 > HCI Event: Number of Completed Packets (0x13) plen 5
            01 40 00 02 00                                   .@...           
[hci0] 20:18:39.104245 > ACL Data: handle 64 flags 0x02 dlen 9
            05 00 04 00 0f 02 c1 f8 4a                       ........J       
[hci0] 20:18:47.897759 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 d3 47 6c e5 c5 78 03 02 01 05 b1     .....Gl..x..... 
{hci0} 20:18:47.898481 @ Device Found: 78:C5:E5:6C:47:D3 (1) rssi -79 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:48.006000 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 d3 47 6c e5 c5 78 03 02 01 05 b1     .....Gl..x..... 
{hci0} 20:18:48.006766 @ Device Found: 78:C5:E5:6C:47:D3 (1) rssi -79 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:48.022528 < HCI Command: LE Create Connection (0x08|0x000d) plen 25
            60 00 30 00 00 00 d3 47 6c e5 c5 78 00 28 00 38  `.0....Gl..x.(.8
            00 00 00 2a 00 00 00 00 00                       ...*.....       
[hci0] 20:18:48.024317 > HCI Event: Command Status (0x0f) plen 4
            00 01 0d 20                                      ...             
[hci0] 20:18:48.111376 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 d3 47 6c e5 c5 78 03 02 01 05 b3     .....Gl..x..... 
{hci0} 20:18:48.114928 @ Device Found: 78:C5:E5:6C:47:D3 (1) rssi -77 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:48.212831 > HCI Event: LE Meta Event (0x3e) plen 15
            02 01 00 00 d3 47 6c e5 c5 78 03 02 01 05 b4     .....Gl..x..... 
{hci0} 20:18:48.216182 @ Device Found: 78:C5:E5:6C:47:D3 (1) rssi -76 flags 0x0000
            02 01 05                                         ...             
[hci0] 20:18:48.323916 > HCI Event: LE Meta Event (0x3e) plen 19
            01 00 41 00 00 00 d3 47 6c e5 c5 78 2d 00 00 00  ..A....Gl..x-...
            2a 00 05                                         *..             
{hci0} 20:18:48.327495 @ Device Connected: 78:C5:E5:6C:47:D3 (1) flags 0x0000
[hci0] 20:18:48.333284 > ACL Data: handle 65 flags 0x02 dlen 16
            0c 00 05 00 12 01 08 00 10 00 20 00 00 00 2c 01  .......... ...,.
[hci0] 20:18:48.349300 < ACL Data: handle 65 flags 0x00 dlen 10
            06 00 05 00 13 01 02 00 00 00                    ..........      
[hci0] 20:18:48.352607 < HCI Command: LE Connection Update (0x08|0x0013) plen 14
            41 00 10 00 20 00 00 00 2c 01 01 00 01 00        A... ...,.....  
[hci0] 20:18:48.383669 < ACL Data: handle 65 flags 0x00 dlen 9
            05 00 04 00 52 2b 00 01 00                       ....R+...       
[hci0] 20:18:48.388568 < ACL Data: handle 65 flags 0x00 dlen 9
            05 00 04 00 52 33 00 01 00                       ....R3...       
[hci0] 20:18:48.387350 > HCI Event: Command Status (0x0f) plen 4
            00 01 13 20                                      ...             
[hci0] 20:18:48.418589 < ACL Data: handle 65 flags 0x00 dlen 9
            05 00 04 00 52 2f 00 01 00                       ....R/...       
[hci0] 20:18:48.425317 < ACL Data: handle 65 flags 0x00 dlen 9
            05 00 04 00 52 20 00 01 00                       ....R ...       
[hci0] 20:18:48.430541 < ACL Data: handle 65 flags 0x00 dlen 13
            09 00 04 00 0e 2a 00 32 00 2e 00 1f 00           .....*.2.....   
[hci0] 20:18:48.502347 > HCI Event: Number of Completed Packets (0x13) plen 5
            01 41 00 02 00                                   .A...           
[hci0] 20:18:48.504306 > HCI Event: Number of Completed Packets (0x13) plen 5
            01 41 00 02 00                                   .A...           
[hci0] 20:18:48.557946 > ACL Data: handle 65 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 f9                          ........        
[hci0] 20:18:48.559036 > ACL Data: handle 65 flags 0x02 dlen 8
            04 00 04 00 1b 32 00 bd                          .....2..        
[hci0] 20:18:48.560295 > HCI Event: Number of Completed Packets (0x13) plen 5
            01 41 00 02 00                                   .A...           
[hci0] 20:18:48.614345 > ACL Data: handle 65 flags 0x02 dlen 9
            05 00 04 00 0f 00 bd f9 46                       ........F       
[hci0] 20:18:54.291631 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 ee                          .....*..        
[hci0] 20:18:54.292623 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 ec                          ........        
[hci0] 20:18:54.292750 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 32 00 c9                          .....2..        
[hci0] 20:18:54.359162 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 ff                          .....*..        
[hci0] 20:18:54.359454 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 f7                          ........        
[hci0] 20:18:54.360633 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 32 00 c0                          .....2..        
[hci0] 20:18:54.561663 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 f9                          .....*..        
[hci0] 20:18:54.564898 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 cd                          ........        
[hci0] 20:18:54.696646 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 02                          .....*..        
[hci0] 20:18:54.698873 > ACL Data: handle 64 flags 0x02 dlen 8
            04 00 04 00 1b 2e 00 f8                          ........        
[hci0] 20:19:10.383417 > ACL Data: handle 65 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 f9                          .....*..        
[hci0] 20:19:10.439511 > ACL Data: handle 65 flags 0x02 dlen 8
            04 00 04 00 1b 2a 00 ff                          .....*..        
[hci0] 20:19:26.411547 < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2
            00 00                                            ..              
[hci0] 20:19:26.414730 > HCI Event: Command Complete (0x0e) plen 4
            01 0c 20 00                                      .. .            
{hci0} 20:19:26.415494 @ Discovering: 0x00 (0)
[hci0] 20:19:28.193302 < HCI Command: Disconnect (0x01|0x0006) plen 3
            41 00 13                                         A..             
[hci0] 20:19:28.197097 > HCI Event: Command Status (0x0f) plen 4
            00 01 06 04                                      ....            
[hci0] 20:19:28.215607 > HCI Event: Disconn Complete (0x05) plen 4
            00 41 00 16                                      .A..            
{hci0} 20:19:28.216171 @ Device Disconnected: 78:C5:E5:6C:47:D3 (1)
[hci0] 20:19:28.313364 < HCI Command: Disconnect (0x01|0x0006) plen 3
            40 00 13                                         @..             
[hci0] 20:19:28.315515 > HCI Event: Command Status (0x0f) plen 4
            00 01 06 04                                      ....            
[hci0] 20:19:28.380626 > HCI Event: Disconn Complete (0x05) plen 4
            00 40 00 16                                      .@..            
{hci0} 20:19:28.381835 @ Device Disconnected: 78:C5:E5:6C:47:A2 (1)


^ permalink raw reply

* [PATCH v3] android: Add README file with instructions
From: Szymon Janc @ 2013-10-29 13:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This file cotains help on how BlueZ for Android should be build, run
and test. Some hints and examples on how BlueZ can be intergrated into
Android are present as well.
---
v3:
 - fixed init service issues pointer by Andrei
 - clarify that bluetoothd needs to be whitelisted to be started by
   bluetooth user
 - note about haltest being also usable on Linux PC

 android/Makefile.am |  2 +-
 android/README      | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+), 1 deletion(-)
 create mode 100644 android/README

diff --git a/android/Makefile.am b/android/Makefile.am
index 22002be..5690e93 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -96,7 +96,7 @@ EXTRA_DIST += android/client/terminal.c \
 		android/client/history.h \
 		android/client/terminal.h
 
-EXTRA_DIST += android/hal-ipc-api.txt
+EXTRA_DIST += android/hal-ipc-api.txt android/README
 
 EXTRA_DIST += android/hardware/bluetooth.h \
 		android/hardware/bt_av.h \
diff --git a/android/README b/android/README
new file mode 100644
index 0000000..3614026
--- /dev/null
+++ b/android/README
@@ -0,0 +1,90 @@
+BlueZ for Android
+*****************
+
+Since Android 4.2 there exists a well standardized HAL interface that the
+Bluetooth stack is expected to provide and which enables the easy replacement
+of the stack of choice on Android. Android BlueZ is intended as a drop-in
+replacement to Android provided Bluetooth stack.
+
+More details about BlueZ for Android architecture and components can be found
+in android/hal-apc-api.txt file.
+
+===============================
+Building and running on Android
+===============================
+
+Build requirements
+==================
+
+- GLib - Android 4.2 or later don't provide GLib and one must provide it in
+'external/bluetooth/glib' folder of Android tree. Sample Android GLib port
+is available at https://code.google.com/p/android-bluez.glib/
+
+- Bionic support - BlueZ requires signalfd and timerfd APIs to be provided
+by libc library. Currently only 'master' branch available at
+https://android.googlesource.com/platform/bionic provides all required
+functionality and running BlueZ on older branch requires backporting missing
+features. Sample Bionic for Android on Intel Architecture (Android-IA) with all
+required features backported is available at
+https://code.google.com/p/android-bluez.bionic/
+
+Runtime requirements
+====================
+
+BlueZ HAL library requires 'bluetoothd' service to be available on Android
+system. This can be done by defining service in init.rc file of targeted board:
+
+service bluetoothd /system/bin/logwrapper /system/bin/bluetoothd
+  class main
+  group bluetooth net_admin
+  disabled
+  oneshot
+
+It is required that bluetooth user could start and stop bluetoothd service by
+setting 'ctl.start' or 'ctl.stop' property. This can be achieved by
+whitelisting bluetooth user and bluetoothd service in init source code.
+
+Required Android init system modifications can be found at
+https://code.google.com/p/android-bluez.system-core/
+
+Downloading and building
+========================
+
+Building for Android requires full Android AOSP source tree. Sample Android-IA
+tree with all required components present is available at
+http://code.google.com/p/android-bluez/
+
+Downloading:
+repo init -u https://code.google.com/p/android-bluez.manifest/ -m topics/bluez
+repo sync
+
+Build for Intel ultrabook:
+'source build/envsetup.sh'
+'lunch core_mesa-eng'
+'make allimages -j8'
+
+After full build is done it is possible to rebuild only BlueZ:
+'cd external/bluetooth/bluez/android/'
+'mm' (or 'mm -B' to force rebuilding of all files)
+'adb sync' to update target device.
+
+=============================
+Building and running on Linux
+=============================
+
+It is possible to build and test BlueZ for Android daemon on Linux (eg. PC).
+Simply follow instructions available at README file in BlueZ top directory.
+Android daemon binary is located at android/bluetoothd. See next section on
+how to test Android daemon on Linux.
+
+=======
+Testing
+=======
+
+BT HAL test tools located in android/haltest is provided for HAL level testing
+of both Android daemon and HAL library. Start it and type 'adapter init' in
+prompt to initialize HAL library. On Android required bluetoothd service will
+be started automatically. On Linux it is required to start android/bluetoothd
+manually before init command timeout. To deinitialize HAL library and stop
+daemon type 'adapter cleanup'. Type 'help' for more information. Tab completion
+is also supported.
\ No newline at end of file
-- 
1.8.4.1


^ permalink raw reply related

* Re: [PATCH] android/daemon: Solves warnings when compiling for Android
From: Marcel Holtmann @ 2013-10-29 13:34 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1383053394-22664-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

> When compiling for Android I get very annoying warnings shown below.
> Though the issue is with android this really helps to clear Android
> build screen.
> 
> external/bluetooth/bluez/android/main.c: In function 'cmd_watch_cb':
> external/bluetooth/bluez/android/main.c:192:3: warning: format '%zd' expects
>  argument of type 'signed size_t', but argument 2 has type 'ssize_t' [-Wformat]
> external/bluetooth/bluez/android/main.c:197:3: warning: format '%zd' expects
>  argument of type 'signed size_t', but argument 2 has type 'ssize_t' [-Wformat]

do we actually know piece inside Android is causing this stupid warning. Is this a bug in bionic and should be fixed.

> ---
> Let me know if this solution is OK and I will change other parts as well.
> 
> android/main.c |    6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/android/main.c b/android/main.c
> index 6ff30a9..63c9eda 100644
> --- a/android/main.c
> +++ b/android/main.c
> @@ -171,7 +171,7 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
> {
> 	char buf[BLUEZ_HAL_MTU];
> 	struct hal_hdr *msg = (void *) buf;
> -	ssize_t ret;
> +	int ret;
> 	int fd;
> 
> 	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
> @@ -189,12 +189,12 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
> 	}
> 
> 	if (ret < (ssize_t) sizeof(*msg)) {

And why is this cast still ssize_t.

> -		error("HAL command too small, terminating (%zd)", ret);
> +		error("HAL command too small, terminating (%d)", ret);
> 		goto fail;
> 	}
> 
> 	if (ret != (ssize_t) (sizeof(*msg) + msg->len)) {

And here as well.

> -		error("Malformed HAL command (%zd bytes), terminating", ret);
> +		error("Malformed HAL command (%d bytes), terminating", ret);
> 		goto fail;
> 	}

Regards

Marcel


^ permalink raw reply

* [PATCH] android/daemon: Solves warnings when compiling for Android
From: Andrei Emeltchenko @ 2013-10-29 13:29 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

When compiling for Android I get very annoying warnings shown below.
Though the issue is with android this really helps to clear Android
build screen.

external/bluetooth/bluez/android/main.c: In function 'cmd_watch_cb':
external/bluetooth/bluez/android/main.c:192:3: warning: format '%zd' expects
  argument of type 'signed size_t', but argument 2 has type 'ssize_t' [-Wformat]
external/bluetooth/bluez/android/main.c:197:3: warning: format '%zd' expects
  argument of type 'signed size_t', but argument 2 has type 'ssize_t' [-Wformat]
---
 Let me know if this solution is OK and I will change other parts as well.

 android/main.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/android/main.c b/android/main.c
index 6ff30a9..63c9eda 100644
--- a/android/main.c
+++ b/android/main.c
@@ -171,7 +171,7 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
 {
 	char buf[BLUEZ_HAL_MTU];
 	struct hal_hdr *msg = (void *) buf;
-	ssize_t ret;
+	int ret;
 	int fd;
 
 	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
@@ -189,12 +189,12 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
 	}
 
 	if (ret < (ssize_t) sizeof(*msg)) {
-		error("HAL command too small, terminating (%zd)", ret);
+		error("HAL command too small, terminating (%d)", ret);
 		goto fail;
 	}
 
 	if (ret != (ssize_t) (sizeof(*msg) + msg->len)) {
-		error("Malformed HAL command (%zd bytes), terminating", ret);
+		error("Malformed HAL command (%d bytes), terminating", ret);
 		goto fail;
 	}
 
-- 
1.7.10.4


^ permalink raw reply related

* [RFC v2 15/15] Bluetooth: Mgmt command for removing connection parameters
From: Andre Guedes @ 2013-10-29 13:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch introduces the MGMT_OP_REMOVE_CONN_PARAMS which removes
from hdev's list the connection parameters from a given device.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/mgmt.h |  6 ++++++
 net/bluetooth/mgmt.c         | 31 +++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index a16924f..92154c4 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -378,6 +378,12 @@ struct mgmt_cp_add_conn_params {
 } __packed;
 #define MGMT_ADD_CONN_PARAMS_SIZE	(MGMT_ADDR_INFO_SIZE + 5)
 
+#define MGMT_OP_REMOVE_CONN_PARAMS	0x002E
+struct mgmt_cp_remove_conn_params {
+	struct mgmt_addr_info addr;
+} __packed;
+#define MGMT_REMOVE_CONN_PARAMS_SIZE	MGMT_ADDR_INFO_SIZE
+
 #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 b8e0f12..5056560 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -80,6 +80,7 @@ static const u16 mgmt_commands[] = {
 	MGMT_OP_SET_STATIC_ADDRESS,
 	MGMT_OP_SET_SCAN_PARAMS,
 	MGMT_OP_ADD_CONN_PARAMS,
+	MGMT_OP_REMOVE_CONN_PARAMS,
 };
 
 static const u16 mgmt_events[] = {
@@ -4127,6 +4128,35 @@ static int add_conn_params(struct sock *sk, struct hci_dev *hdev, void *cp_data,
 			    MGMT_STATUS_SUCCESS, NULL, 0);
 }
 
+static int remove_conn_params(struct sock *sk, struct hci_dev *hdev,
+			      void *cp_data, u16 len)
+{
+	struct mgmt_cp_remove_conn_params *cp = cp_data;
+	u8 status;
+	u8 addr_type;
+
+	if (!bdaddr_type_is_le(cp->addr.type))
+		return cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_CONN_PARAMS,
+				    MGMT_STATUS_NOT_SUPPORTED, NULL, 0);
+
+	status = mgmt_le_support(hdev);
+	if (status)
+		return cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_CONN_PARAMS,
+				    status, NULL, 0);
+
+	if (cp->addr.type == BDADDR_LE_PUBLIC)
+		addr_type = ADDR_LE_DEV_PUBLIC;
+	else
+		addr_type = ADDR_LE_DEV_RANDOM;
+
+	hci_remove_conn_params(hdev, &cp->addr.bdaddr, addr_type);
+
+	hci_remove_pending_auto_conn(hdev, &cp->addr.bdaddr, addr_type);
+
+	return cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_CONN_PARAMS,
+			    MGMT_STATUS_SUCCESS, NULL, 0);
+}
+
 static const struct mgmt_handler {
 	int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
 		     u16 data_len);
@@ -4179,6 +4209,7 @@ static const struct mgmt_handler {
 	{ set_static_address,     false, MGMT_SET_STATIC_ADDRESS_SIZE },
 	{ set_scan_params,        false, MGMT_SET_SCAN_PARAMS_SIZE },
 	{ add_conn_params,        false, MGMT_ADD_CONN_PARAMS_SIZE },
+	{ remove_conn_params,     false, MGMT_REMOVE_CONN_PARAMS_SIZE },
 };
 
 
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 14/15] Bluetooth: Mgmt command for adding connection parameters
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch introduces a new Mgmt command (MGMT_OP_ADD_CONN_PARAMS)
to specify the connection parameters the kernel should use when
establishing connections to a certain device. Moreover, this command
also specifies the auto connection option the device requires.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/mgmt.h |  9 +++++++++
 net/bluetooth/mgmt.c         | 48 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 518c5c8..a16924f 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -369,6 +369,15 @@ struct mgmt_cp_set_scan_params {
 } __packed;
 #define MGMT_SET_SCAN_PARAMS_SIZE	4
 
+#define MGMT_OP_ADD_CONN_PARAMS		0x002D
+struct mgmt_cp_add_conn_params {
+	struct mgmt_addr_info addr;
+	__u8 auto_connect;
+	__le16 min_conn_interval;
+	__le16 max_conn_interval;
+} __packed;
+#define MGMT_ADD_CONN_PARAMS_SIZE	(MGMT_ADDR_INFO_SIZE + 5)
+
 #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 d396e47..b8e0f12 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -79,6 +79,7 @@ static const u16 mgmt_commands[] = {
 	MGMT_OP_SET_BREDR,
 	MGMT_OP_SET_STATIC_ADDRESS,
 	MGMT_OP_SET_SCAN_PARAMS,
+	MGMT_OP_ADD_CONN_PARAMS,
 };
 
 static const u16 mgmt_events[] = {
@@ -4080,6 +4081,52 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
 	return err;
 }
 
+static int add_conn_params(struct sock *sk, struct hci_dev *hdev, void *cp_data,
+			  u16 len)
+{
+	struct mgmt_cp_add_conn_params *cp = cp_data;
+	u8 status;
+	u8 addr_type;
+	int err;
+
+	if (!bdaddr_type_is_le(cp->addr.type))
+		return cmd_complete(sk, hdev->id, MGMT_OP_ADD_CONN_PARAMS,
+				    MGMT_STATUS_NOT_SUPPORTED, NULL, 0);
+
+	status = mgmt_le_support(hdev);
+	if (status)
+		return cmd_complete(sk, hdev->id, MGMT_OP_ADD_CONN_PARAMS,
+				    status, NULL, 0);
+
+	if (cp->addr.type == BDADDR_LE_PUBLIC)
+		addr_type = ADDR_LE_DEV_PUBLIC;
+	else
+		addr_type = ADDR_LE_DEV_RANDOM;
+
+	err = hci_add_conn_params(hdev, &cp->addr.bdaddr, addr_type,
+				  cp->auto_connect,
+				  __le16_to_cpu(cp->min_conn_interval),
+				  __le16_to_cpu(cp->max_conn_interval));
+	if (err)
+		return cmd_complete(sk, hdev->id, MGMT_OP_ADD_CONN_PARAMS,
+				    MGMT_STATUS_FAILED, NULL, 0);
+
+	if (cp->auto_connect == HCI_AUTO_CONN_ALWAYS) {
+		err = hci_add_pending_auto_conn(hdev, &cp->addr.bdaddr,
+						addr_type);
+		if (err) {
+			hci_remove_conn_params(hdev, &cp->addr.bdaddr,
+					       addr_type);
+			return cmd_complete(sk, hdev->id,
+					    MGMT_OP_ADD_CONN_PARAMS,
+					    MGMT_STATUS_FAILED, NULL, 0);
+		}
+	}
+
+	return cmd_complete(sk, hdev->id, MGMT_OP_ADD_CONN_PARAMS,
+			    MGMT_STATUS_SUCCESS, NULL, 0);
+}
+
 static const struct mgmt_handler {
 	int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
 		     u16 data_len);
@@ -4131,6 +4178,7 @@ static const struct mgmt_handler {
 	{ set_bredr,              false, MGMT_SETTING_SIZE },
 	{ set_static_address,     false, MGMT_SET_STATIC_ADDRESS_SIZE },
 	{ set_scan_params,        false, MGMT_SET_SCAN_PARAMS_SIZE },
+	{ add_conn_params,        false, MGMT_ADD_CONN_PARAMS_SIZE },
 };
 
 
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 13/15] Bluetooth: Add thread-safe version of helpers
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch adds the thread-safe version of helper functions to add
and remove pending auto connections. These helpers will be used in
next patches to implementing the Mgmt add/remove connection
parameters commands.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/hci_core.h |  4 ++++
 net/bluetooth/hci_core.c         | 20 ++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 379bb36..2659123 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -779,8 +779,12 @@ bool hci_has_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 			       u8 addr_type);
 int __hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 				u8 addr_type);
+int hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+			      u8 addr_type);
 void __hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 				    u8 addr_type);
+void hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+				  u8 addr_type);
 
 bool hci_is_scan_and_conn_supported(struct hci_dev *hdev);
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 63a56f5..5d7fd3d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3029,6 +3029,18 @@ int __hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 	return 0;
 }
 
+int hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+			      u8 addr_type)
+{
+	int err;
+
+	hci_dev_lock(hdev);
+	err = __hci_add_pending_auto_conn(hdev, addr, addr_type);
+	hci_dev_unlock(hdev);
+
+	return err;
+}
+
 /* This function requires the caller holds hdev->lock */
 void __hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 				    u8 addr_type)
@@ -3051,6 +3063,14 @@ void __hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 	}
 }
 
+void hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+				  u8 addr_type)
+{
+	hci_dev_lock(hdev);
+	__hci_remove_pending_auto_conn(hdev, addr, addr_type);
+	hci_dev_unlock(hdev);
+}
+
 /* This function requires the caller holds hdev->lock */
 static void __clear_pending_auto_conn(struct hci_dev *hdev)
 {
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 12/15] Bleutooth: Add support for auto connect options
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch adds support for the HCI_AUTO_CONN_ALWAYS and HCI_AUTO_
CONN_LINK_LOSS options from struct hci_conn_params.

The HCI_AUTO_CONN_ALWAYS option configures the kernel to always re-
establish the connection, no matter the reason the connection was
terminated. This feature is required by some LE profiles such as
HID over GATT, Health Thermometer and Blood Pressure. These profiles
require the host autonomously connect to the device as soon as it
enters in connectable mode (start advertising) so the device is able
to delivery a notification or indication.

The BT_AUTO_CONN_LINK_LOSS option configures the kernel to re-
establish the connection in case the connection was terminated due
to a link loss. This feature is required by the majority of LE
profiles such as Proximity, Find Me, Cycling Speed and Cadence and
Time.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 net/bluetooth/hci_event.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index e48601d..b2d8aee 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1785,6 +1785,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 	struct hci_conn *conn;
 	u8 type;
 	bool send_mgmt_event = false;
+	struct hci_conn_params *params;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
 
@@ -1817,6 +1818,31 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 	if (conn->type == ACL_LINK && conn->flush_key)
 		hci_remove_link_key(hdev, &conn->dst);
 
+	params = hci_find_conn_params(hdev, &conn->dst, conn->dst_type);
+	if (params) {
+		int err;
+
+		switch (params->auto_connect) {
+		case HCI_AUTO_CONN_LINK_LOSS:
+			if (ev->reason != HCI_ERROR_CONNECTION_TIMEOUT)
+				break;
+			/* Fall through */
+
+		case HCI_AUTO_CONN_ALWAYS:
+			err = __hci_add_pending_auto_conn(hdev, &conn->dst,
+							  conn->dst_type);
+			if (err)
+				BT_ERR("Failed to add pending auto connection "
+				       " %d", err);
+			break;
+
+		default:
+			break;
+		}
+
+		hci_conn_params_put(params);
+	}
+
 	type = conn->type;
 	hci_proto_disconn_cfm(conn, ev->reason);
 	hci_conn_del(conn);
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 11/15] Bluetooth: Auto connection and power on
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch implements a fixup required by auto connection mechanism
in order to work properly after a power on.

When hdev is closed (e.g. Mgmt power off command, RFKILL or controller
is reset), the ongoing active connections are silently dropped by the
controller (no Disconnection Complete Event is sent to host). For that
reason, the devices that require HCI_AUTO_CONN_ALWAYS are not added to
hdev->pending_auto_conn list and they won't auto connect. So to fix
this issue, after adapter is powered on, we should add all HCI_AUTO_
CONN_ALWAYS address to hdev->pending_auto_conn list. Besides that, we
always have to check if there are pending auto connections and start
the background scanning if it is the case.

This way, the auto connection mechanism works propely after a power
off and power on sequence as well as RFKILL block/unblock.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/hci_core.h |  2 ++
 net/bluetooth/hci_core.c         | 49 ++++++++++++++++++++++++++++++++++++++++
 net/bluetooth/mgmt.c             |  2 ++
 3 files changed, 53 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 322918f..379bb36 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -786,6 +786,8 @@ bool hci_is_scan_and_conn_supported(struct hci_dev *hdev);
 
 void hci_check_background_scan(struct hci_dev *hdev);
 
+void __hci_fixup_auto_conn(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_core.c b/net/bluetooth/hci_core.c
index 44d3f99..63a56f5 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3090,6 +3090,55 @@ void hci_check_background_scan(struct hci_dev *hdev)
 		BT_ERR("Failed to start background scanning: err %d", err);
 }
 
+/* This functions implements a fixup required by auto connection mechanism
+ * in order to work properly after a power on.
+ *
+ * When hdev is closed (e.g. Mgmt power off command, RFKILL or controller is
+ * reset), the ongoing active connections are silently dropped by the
+ * by the controller (no Disconnection Complete Event is sent to host). For
+ * that reason, the devices that require HCI_AUTO_CONN_ALWAYS are not add to
+ * hdev->pending_auto_conn list and they won't auto connect. So to fix this
+ * issue, after adapter is powered on, we should add all HCI_AUTO_CONN_ALWAYS
+ * address to hdev->pending_auto_conn list. Besides that, we always have to
+ * check if there are pending auto connections and start the background
+ * scanning if it is the case.
+ *
+ * This function requires the caller holds hdev->lock.
+ */
+void __hci_fixup_auto_conn(struct hci_dev *hdev)
+{
+	struct hci_conn_params *p;
+	struct bdaddr_list *entry;
+
+	list_for_each_entry(p, &hdev->conn_params, list) {
+		if (p->auto_connect != HCI_AUTO_CONN_ALWAYS)
+			continue;
+
+		entry = __find_pending_auto_conn(hdev, &p->addr, p->addr_type);
+		if (entry)
+			continue;
+
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+		if (!entry) {
+			BT_ERR("Out of memory of auto connection");
+			return;
+		}
+
+		bacpy(&entry->bdaddr, &p->addr);
+		entry->bdaddr_type = p->addr_type;
+		list_add(&entry->list, &hdev->pending_auto_conn);
+	}
+
+	if (!list_empty(&hdev->pending_auto_conn)) {
+		int err;
+
+		err = start_background_scan(hdev);
+		if (err)
+			BT_ERR("Failed to start background scanning: err %d",
+			       err);
+	}
+}
+
 static void inquiry_complete(struct hci_dev *hdev, u8 status)
 {
 	if (status) {
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0e329e5..d396e47 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4255,6 +4255,8 @@ static void powered_complete(struct hci_dev *hdev, u8 status)
 
 	hci_dev_lock(hdev);
 
+	__hci_fixup_auto_conn(hdev);
+
 	mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
 
 	new_settings(hdev, match.sk);
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 10/15] Bluetooth: Temporarily stop background scanning on discovery
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

If the user send a mgmt start discovery command while the background
scanning is running, we should temporarily stop it. Once the discovery
finishes, we start the background scanning again.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 net/bluetooth/hci_core.c |  5 +++++
 net/bluetooth/mgmt.c     | 12 ++++++++----
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 79debc3..44d3f99 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1496,6 +1496,11 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state)
 
 	switch (state) {
 	case DISCOVERY_STOPPED:
+		/* Check the background scanning since it may have been
+		 * temporarily stopped by the start discovery command.
+		 */
+		hci_check_background_scan(hdev);
+
 		if (hdev->discovery.state != DISCOVERY_STARTING)
 			mgmt_discovering(hdev, 0);
 		break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 22cf547..0e329e5 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3280,11 +3280,15 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
 			goto failed;
 		}
 
+		/* If controller is scanning, it means the background scanning
+		 * is running. Thus, we should temporarily stop it in order to
+		 * set the discovery scanning parameters.
+		 */
 		if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
-			err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
-					 MGMT_STATUS_BUSY);
-			mgmt_pending_remove(cmd);
-			goto failed;
+			memset(&enable_cp, 0, sizeof(enable_cp));
+			enable_cp.enable = LE_SCAN_DISABLE;
+			hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
+				    sizeof(enable_cp), &enable_cp);
 		}
 
 		memset(&param_cp, 0, sizeof(param_cp));
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 09/15] Bluetooth: Introduce LE auto connection infrastructure
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch introduces the LE auto connection infrastructure.
This infrastructure will be used to implement the auto_connect
options from hci_conn_params.

The auto connection mechanism works as follows: When the first
device address is inserted into hdev->pending_auto_con list, we
start the background scanning. Once the target device is found
in range, the kernel creates the connection. If connection is
established successfully, the device address is removed from
hdev->pending_auto_conn list. Finally, when the last device
address is removed, the background scanning is stopped.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/hci_core.h |   2 +
 net/bluetooth/hci_conn.c         |   6 ++
 net/bluetooth/hci_core.c         | 115 +++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_event.c        |  43 +++++++++++++++
 4 files changed, 166 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 0049036..322918f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -784,6 +784,8 @@ void __hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 
 bool hci_is_scan_and_conn_supported(struct hci_dev *hdev);
 
+void hci_check_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 b52bcb2..bbe3cab 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -544,6 +544,12 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
 
 done:
 	hci_dev_unlock(hdev);
+
+	/* Check the background scanning since it may have been temporarily
+	 * stopped if the controller doesn't support scanning and creating
+	 * connection at the same time.
+	 */
+	hci_check_background_scan(hdev);
 }
 
 static int hci_create_le_conn(struct hci_conn *conn)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 19624d1..79debc3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2923,6 +2923,72 @@ bool hci_has_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 	return res;
 }
 
+static void start_background_scan_complete(struct hci_dev *hdev, u8 status)
+{
+	if (status)
+		BT_DBG("HCI request failed to start background scanning: "
+		       "status 0x%2.2x", status);
+}
+
+static int start_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;
+
+	if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+		return 0;
+
+	BT_DBG("%s", hdev->name);
+
+	hci_req_init(&req, hdev);
+
+	memset(&param_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),
+		    &param_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);
+
+	return hci_req_run(&req, start_background_scan_complete);
+}
+
+static void stop_background_scan_complete(struct hci_dev *hdev, u8 status)
+{
+	if (status)
+		BT_DBG("HCI request failed to stop background scanning: "
+		       "status 0x%2.2x", status);
+}
+
+static int stop_background_scan(struct hci_dev *hdev)
+{
+	struct hci_cp_le_set_scan_enable cp;
+	struct hci_request req;
+
+	if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+		return 0;
+
+	/* If device discovery is running, background scanning is stopped so
+	 * we return sucess.
+	 */
+	if (hdev->discovery.state == DISCOVERY_FINDING)
+		return 0;
+
+	hci_req_init(&req, hdev);
+
+	memset(&cp, 0, sizeof(cp));
+	cp.enable = LE_SCAN_DISABLE;
+	hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+
+	return hci_req_run(&req, stop_background_scan_complete);
+}
+
 /* This function requires the caller holds hdev->lock */
 int __hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 				u8 addr_type)
@@ -2940,6 +3006,19 @@ int __hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 	bacpy(&entry->bdaddr, addr);
 	entry->bdaddr_type = addr_type;
 
+	/* If there is no pending auto connection, the background scanning
+	 * is not runnning. So we should start it.
+	 */
+	if (list_empty(&hdev->pending_auto_conn)) {
+		int err;
+
+		err = start_background_scan(hdev);
+		if (err) {
+			kfree(entry);
+			return err;
+		}
+	}
+
 	list_add(&entry->list, &hdev->pending_auto_conn);
 
 	return 0;
@@ -2957,6 +3036,14 @@ void __hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 
 	list_del(&entry->list);
 	kfree(entry);
+
+	if (list_empty(&hdev->pending_auto_conn)) {
+		int err;
+
+		err = stop_background_scan(hdev);
+		if (err)
+			BT_ERR("Failed to run HCI request: err %d", err);
+	}
 }
 
 /* This function requires the caller holds hdev->lock */
@@ -2970,6 +3057,34 @@ static void __clear_pending_auto_conn(struct hci_dev *hdev)
 	}
 }
 
+/* This function starts the background scanning in case there is still
+ * pending auto connections.
+ */
+void hci_check_background_scan(struct hci_dev *hdev)
+{
+	struct hci_conn *conn;
+	int err;
+
+	if (list_empty(&hdev->pending_auto_conn))
+		return;
+
+	if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+		return;
+
+	/* If the controller is connecting but it doesn't support scanning
+	 * scanning and connecting at the same time we don't start the
+	 * background scanning now. It will be started once the connection
+	 * is established.
+	 */
+	conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+	if (conn && !hci_is_scan_and_conn_supported(hdev))
+		return;
+
+	err = start_background_scan(hdev);
+	if (err)
+		BT_ERR("Failed to start background scanning: err %d", err);
+}
+
 static void inquiry_complete(struct hci_dev *hdev, u8 status)
 {
 	if (status) {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 8b7cd37..e48601d 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3547,8 +3547,49 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 	hci_proto_connect_cfm(conn, ev->status);
 
+	__hci_remove_pending_auto_conn(hdev, &ev->bdaddr, ev->bdaddr_type);
+
 unlock:
 	hci_dev_unlock(hdev);
+
+	/* Check the background scanning since it may have been temporarily
+	 * stopped if the controller doesn't support scanning and creating
+	 * connection at the same time.
+	 */
+	hci_check_background_scan(hdev);
+}
+
+static void check_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+				    u8 addr_type)
+{
+	struct hci_conn *conn;
+	u8 bdaddr_type;
+
+	if (!hci_has_pending_auto_conn(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)) {
+		switch (PTR_ERR(conn)) {
+		case -EBUSY:
+			/* When hci_connect() returns EBUSY it means there is
+			 * already an LE connection attempt going on. Since the
+			 * controller supports only one connection attempt at
+			 * the time, we simply return.
+			 */
+			return;
+		default:
+			BT_ERR("Failed to auto connect: err %ld",
+			       PTR_ERR(conn));
+			return;
+		}
+	}
 }
 
 static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -3560,6 +3601,8 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
 	while (num_reports--) {
 		struct hci_ev_le_advertising_info *ev = ptr;
 
+		check_pending_auto_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);
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 08/15] Bluetooth: Move is_scan_and_conn_supported() to hci_core
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch adds the "hci_" prefix and moves the is_scan_and_conn_
supported() helper to hci_core so it can be reused in hci_core by
the next patch.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/hci_core.h |  2 ++
 net/bluetooth/hci_conn.c         | 13 +------------
 net/bluetooth/hci_core.c         | 11 +++++++++++
 3 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index e85b37e..0049036 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -782,6 +782,8 @@ int __hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 void __hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
 				    u8 addr_type);
 
+bool hci_is_scan_and_conn_supported(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 075d070..b52bcb2 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -546,17 +546,6 @@ done:
 	hci_dev_unlock(hdev);
 }
 
-/* Check if controller supports creating a connection while scanning is
- * runnning.
- */
-static bool is_scan_and_conn_supported(struct hci_dev *hdev)
-{
-	u8 mask = BIT(6) | BIT(7);
-
-	/* Return true if both bits are set */
-	return (hdev->le_states[2] & mask) == mask;
-}
-
 static int hci_create_le_conn(struct hci_conn *conn)
 {
 	struct hci_dev *hdev = conn->hdev;
@@ -571,7 +560,7 @@ static int hci_create_le_conn(struct hci_conn *conn)
 	 * Otherwise, LE Create Connection command fails.
 	 */
 	if (test_bit(HCI_LE_SCAN, &hdev->dev_flags) &&
-	    !is_scan_and_conn_supported(hdev)) {
+	    !hci_is_scan_and_conn_supported(hdev)) {
 		struct hci_cp_le_set_scan_enable enable_cp;
 
 		memset(&enable_cp, 0, sizeof(enable_cp));
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 94c390b..19624d1 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -4496,3 +4496,14 @@ static void hci_cmd_work(struct work_struct *work)
 		}
 	}
 }
+
+/* Check if controller supports creating a connection while scanning is
+ * runnning.
+ */
+bool hci_is_scan_and_conn_supported(struct hci_dev *hdev)
+{
+	u8 mask = BIT(6) | BIT(7);
+
+	/* Return true if both bits are set */
+	return (hdev->le_states[2] & mask) == mask;
+}
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 07/15] Bluetooth: Introduce hdev->pending_auto_conn list
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch introduces the hdev->pending_auto_conn list which holds
the device addresses the kernel should autonomously connect. It also
introduces some helper functions to manipulate the list.

The list and helper functions will be used by the next patch which
implements the LE auto connection infrastructure.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/hci_core.h |  9 +++++
 net/bluetooth/hci_core.c         | 84 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 64911aa..e85b37e 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -273,6 +273,8 @@ struct hci_dev {
 
 	struct list_head	conn_params;
 
+	struct list_head	pending_auto_conn;
+
 	struct hci_dev_stats	stat;
 
 	atomic_t		promisc;
@@ -773,6 +775,13 @@ struct hci_conn_params *hci_find_conn_params(struct hci_dev *hdev,
 					   bdaddr_t *addr, u8 addr_type);
 void hci_conn_params_put(struct hci_conn_params *params);
 
+bool hci_has_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+			       u8 addr_type);
+int __hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+				u8 addr_type);
+void __hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+				    u8 addr_type);
+
 int hci_uuids_clear(struct hci_dev *hdev);
 
 int hci_link_keys_clear(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0a278da..94c390b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2888,6 +2888,88 @@ static void __clear_conn_params(struct hci_dev *hdev)
 		__remove_conn_params(params);
 }
 
+static struct bdaddr_list *__find_pending_auto_conn(struct hci_dev *hdev,
+						    bdaddr_t *addr,
+						    u8 addr_type)
+{
+	struct bdaddr_list *entry;
+
+	list_for_each_entry(entry, &hdev->pending_auto_conn, list) {
+		if (bacmp(&entry->bdaddr, addr))
+			continue;
+		if (entry->bdaddr_type != addr_type)
+			continue;
+
+		return entry;
+	}
+
+	return NULL;
+}
+
+bool hci_has_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+			       u8 addr_type)
+{
+	bool res;
+
+	hci_dev_lock(hdev);
+
+	if (__find_pending_auto_conn(hdev, addr, addr_type))
+		res = true;
+	else
+		res = false;
+
+	hci_dev_unlock(hdev);
+
+	return res;
+}
+
+/* This function requires the caller holds hdev->lock */
+int __hci_add_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+				u8 addr_type)
+{
+	struct bdaddr_list *entry;
+
+	entry = __find_pending_auto_conn(hdev, addr, addr_type);
+	if (entry)
+		return 0;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	bacpy(&entry->bdaddr, addr);
+	entry->bdaddr_type = addr_type;
+
+	list_add(&entry->list, &hdev->pending_auto_conn);
+
+	return 0;
+}
+
+/* This function requires the caller holds hdev->lock */
+void __hci_remove_pending_auto_conn(struct hci_dev *hdev, bdaddr_t *addr,
+				    u8 addr_type)
+{
+	struct bdaddr_list *entry;
+
+	entry = __find_pending_auto_conn(hdev, addr, addr_type);
+	if (!entry)
+		return;
+
+	list_del(&entry->list);
+	kfree(entry);
+}
+
+/* This function requires the caller holds hdev->lock */
+static void __clear_pending_auto_conn(struct hci_dev *hdev)
+{
+	struct bdaddr_list *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &hdev->pending_auto_conn, list) {
+		list_del(&entry->list);
+		kfree(entry);
+	}
+}
+
 static void inquiry_complete(struct hci_dev *hdev, u8 status)
 {
 	if (status) {
@@ -2999,6 +3081,7 @@ struct hci_dev *hci_alloc_dev(void)
 	INIT_LIST_HEAD(&hdev->long_term_keys);
 	INIT_LIST_HEAD(&hdev->remote_oob_data);
 	INIT_LIST_HEAD(&hdev->conn_params);
+	INIT_LIST_HEAD(&hdev->pending_auto_conn);
 	INIT_LIST_HEAD(&hdev->conn_hash.list);
 
 	INIT_WORK(&hdev->rx_work, hci_rx_work);
@@ -3185,6 +3268,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
 	hci_smp_ltks_clear(hdev);
 	hci_remote_oob_data_clear(hdev);
 	__clear_conn_params(hdev);
+	__clear_pending_auto_conn(hdev);
 	hci_dev_unlock(hdev);
 
 	hci_dev_put(hdev);
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 06/15] Bluetooth: Use connection parameters if any
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch changes hci_connect_le() so it uses the connection
parameters specified for the certain device. If no parameters
were configured, we use the default values.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 net/bluetooth/hci_conn.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 195b78f..075d070 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -608,6 +608,7 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
 {
 	struct hci_conn *conn;
 	int err;
+	struct hci_conn_params *params;
 
 	if (test_bit(HCI_ADVERTISING, &hdev->flags))
 		return ERR_PTR(-ENOTSUPP);
@@ -652,8 +653,16 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
 	conn->sec_level = BT_SECURITY_LOW;
 	conn->pending_sec_level = sec_level;
 	conn->auth_type = auth_type;
-	conn->conn_interval_min = hdev->le_conn_min_interval;
-	conn->conn_interval_max = hdev->le_conn_max_interval;
+
+	params = hci_find_conn_params(hdev, &conn->dst, conn->dst_type);
+	if (params) {
+		conn->conn_interval_min = params->conn_interval_min;
+		conn->conn_interval_max = params->conn_interval_max;
+		hci_conn_params_put(params);
+	} else {
+		conn->conn_interval_min = hdev->le_conn_min_interval;
+		conn->conn_interval_max = hdev->le_conn_max_interval;
+	}
 
 	err = hci_create_le_conn(conn);
 	if (err)
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 05/15] Bluetooth: Make find_conn_param() helper non-local
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch makes the find_conn_param() helper non-local by adding the
hci_ prefix and declaring it in hci_core.h. This helper will be used
in hci_conn.c to get the connection parameters when establishing
connections.

Since hci_find_conn_param() returns a reference to the hci_conn_param
object, it was added a refcount to hci_conn_param to control its
lifetime. This way, we avoid bugs such as use-after-free.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/hci_core.h |  5 +++++
 net/bluetooth/hci_core.c         | 45 ++++++++++++++++++++++++++++++++++------
 2 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 22d16d9..64911aa 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -378,6 +378,8 @@ struct hci_chan {
 };
 
 struct hci_conn_params {
+	struct kref refcount;
+
 	struct list_head list;
 
 	bdaddr_t addr;
@@ -767,6 +769,9 @@ int hci_add_conn_params(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
 			u16 conn_interval_max);
 void hci_remove_conn_params(struct hci_dev *hdev, bdaddr_t *addr,
 			    u8 addr_type);
+struct hci_conn_params *hci_find_conn_params(struct hci_dev *hdev,
+					   bdaddr_t *addr, u8 addr_type);
+void hci_conn_params_put(struct hci_conn_params *params);
 
 int hci_uuids_clear(struct hci_dev *hdev);
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index fa41a58..0a278da 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2771,8 +2771,33 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 	return mgmt_device_unblocked(hdev, bdaddr, type);
 }
 
-static struct hci_conn_params *find_conn_params(struct hci_dev *hdev,
-						bdaddr_t *addr, u8 addr_type)
+static void hci_conn_params_get(struct hci_conn_params *params)
+{
+	kref_get(&params->refcount);
+}
+
+static void release_hci_conn_params(struct kref *kref)
+{
+	struct hci_conn_params *params = container_of(kref,
+						    struct hci_conn_params,
+						    refcount);
+
+	kfree(params);
+}
+
+void hci_conn_params_put(struct hci_conn_params *params)
+{
+	kref_put(&params->refcount, release_hci_conn_params);
+}
+
+/* Lookup hci_conn_params in hdev->conn_params list.
+ *
+ * Return a reference to hci_conn_params object with refcount incremented.
+ * The caller should drop its reference by using hci_conn_params_put(). If
+ * hci_conn_params is not found, NULL is returned.
+ */
+struct hci_conn_params *hci_find_conn_params(struct hci_dev *hdev,
+					     bdaddr_t *addr, u8 addr_type)
 {
 	struct hci_conn_params *params;
 
@@ -2784,6 +2809,8 @@ static struct hci_conn_params *find_conn_params(struct hci_dev *hdev,
 		if (params->addr_type != addr_type)
 			continue;
 
+		hci_conn_params_get(params);
+
 		rcu_read_unlock();
 		return params;
 	}
@@ -2798,14 +2825,18 @@ int hci_add_conn_params(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
 {
 	struct hci_conn_params *params;
 
-	params = find_conn_params(hdev, addr, addr_type);
-	if (params)
+	params = hci_find_conn_params(hdev, addr, addr_type);
+	if (params) {
+		hci_conn_params_put(params);
 		return -EEXIST;
+	}
 
 	params = kmalloc(sizeof(*params), GFP_KERNEL);
 	if (!params)
 		return -ENOMEM;
 
+	kref_init(&params->refcount);
+
 	bacpy(&params->addr, addr);
 	params->addr_type = addr_type;
 	params->auto_connect = auto_connect;
@@ -2827,20 +2858,22 @@ static void __remove_conn_params(struct hci_conn_params *params)
 	list_del_rcu(&params->list);
 	synchronize_rcu();
 
-	kfree(params);
+	hci_conn_params_put(params);
 }
 
 void hci_remove_conn_params(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
 {
 	struct hci_conn_params *params;
 
-	params = find_conn_params(hdev, addr, addr_type);
+	params = hci_find_conn_params(hdev, addr, addr_type);
 	if (!params)
 		return;
 
 	hci_dev_lock(hdev);
 	__remove_conn_params(params);
 	hci_dev_unlock(hdev);
+
+	hci_conn_params_put(params);
 }
 
 /* Remove all elements from hdev->conn_params list.
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 04/15] Bluetooth: Introduce connection parameters list
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch adds to hdev the connection parameters list (hdev->
conn_params). The elements from this list (struct hci_conn_params)
contains the connection parameters (for now, minimum and maximum
connection interval) that should be used during the connection
establishment.

The struct hci_conn_params also defines the 'auto_connect' field
which will be used to implement the auto connection mechanism.

Moreover, this patch adds helper functions to manipulate hdev->conn_
params list. Some of these functions are also declared in hci_core.h
since they will be used outside hci_core.c in upcoming patches.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/hci_core.h | 24 +++++++++++
 net/bluetooth/hci_core.c         | 86 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 037a7b5..22d16d9 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -271,6 +271,8 @@ struct hci_dev {
 
 	struct list_head	remote_oob_data;
 
+	struct list_head	conn_params;
+
 	struct hci_dev_stats	stat;
 
 	atomic_t		promisc;
@@ -375,6 +377,22 @@ struct hci_chan {
 	__u8		state;
 };
 
+struct hci_conn_params {
+	struct list_head list;
+
+	bdaddr_t addr;
+	u8 addr_type;
+
+	enum {
+		HCI_AUTO_CONN_DISABLED,
+		HCI_AUTO_CONN_ALWAYS,
+		HCI_AUTO_CONN_LINK_LOSS,
+	} auto_connect;
+
+	u16 conn_interval_min;
+	u16 conn_interval_max;
+};
+
 extern struct list_head hci_dev_list;
 extern struct list_head hci_cb_list;
 extern rwlock_t hci_dev_list_lock;
@@ -744,6 +762,12 @@ int hci_blacklist_clear(struct hci_dev *hdev);
 int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 
+int hci_add_conn_params(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
+			u8 auto_connect, u16 conn_interval_min,
+			u16 conn_interval_max);
+void hci_remove_conn_params(struct hci_dev *hdev, bdaddr_t *addr,
+			    u8 addr_type);
+
 int hci_uuids_clear(struct hci_dev *hdev);
 
 int hci_link_keys_clear(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 6ccc4eb..fa41a58 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2771,6 +2771,90 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 	return mgmt_device_unblocked(hdev, bdaddr, type);
 }
 
+static struct hci_conn_params *find_conn_params(struct hci_dev *hdev,
+						bdaddr_t *addr, u8 addr_type)
+{
+	struct hci_conn_params *params;
+
+	rcu_read_lock();
+
+	list_for_each_entry(params, &hdev->conn_params, list) {
+		if (bacmp(&params->addr, addr))
+			continue;
+		if (params->addr_type != addr_type)
+			continue;
+
+		rcu_read_unlock();
+		return params;
+	}
+
+	rcu_read_unlock();
+	return NULL;
+}
+
+int hci_add_conn_params(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
+		       u8 auto_connect, u16 conn_interval_min,
+		       u16 conn_interval_max)
+{
+	struct hci_conn_params *params;
+
+	params = find_conn_params(hdev, addr, addr_type);
+	if (params)
+		return -EEXIST;
+
+	params = kmalloc(sizeof(*params), GFP_KERNEL);
+	if (!params)
+		return -ENOMEM;
+
+	bacpy(&params->addr, addr);
+	params->addr_type = addr_type;
+	params->auto_connect = auto_connect;
+	params->conn_interval_min = conn_interval_min;
+	params->conn_interval_max = conn_interval_max;
+
+	hci_dev_lock(hdev);
+	list_add_rcu(&params->list, &hdev->conn_params);
+	hci_dev_unlock(hdev);
+	return 0;
+}
+
+/* Remove from hdev->conn_params and free hci_conn_params.
+ *
+ * This function requires the caller holds hdev->lock.
+ */
+static void __remove_conn_params(struct hci_conn_params *params)
+{
+	list_del_rcu(&params->list);
+	synchronize_rcu();
+
+	kfree(params);
+}
+
+void hci_remove_conn_params(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
+{
+	struct hci_conn_params *params;
+
+	params = find_conn_params(hdev, addr, addr_type);
+	if (!params)
+		return;
+
+	hci_dev_lock(hdev);
+	__remove_conn_params(params);
+	hci_dev_unlock(hdev);
+}
+
+/* Remove all elements from hdev->conn_params list.
+ *
+ * This function requires the caller holds hdev->lock.
+ */
+static void __clear_conn_params(struct hci_dev *hdev)
+{
+	struct hci_conn_params *params, *tmp;
+
+	list_for_each_entry_safe(params, tmp, &hdev->conn_params, list)
+		__remove_conn_params(params);
+}
+
 static void inquiry_complete(struct hci_dev *hdev, u8 status)
 {
 	if (status) {
@@ -2881,6 +2965,7 @@ struct hci_dev *hci_alloc_dev(void)
 	INIT_LIST_HEAD(&hdev->link_keys);
 	INIT_LIST_HEAD(&hdev->long_term_keys);
 	INIT_LIST_HEAD(&hdev->remote_oob_data);
+	INIT_LIST_HEAD(&hdev->conn_params);
 	INIT_LIST_HEAD(&hdev->conn_hash.list);
 
 	INIT_WORK(&hdev->rx_work, hci_rx_work);
@@ -3066,6 +3151,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
 	hci_link_keys_clear(hdev);
 	hci_smp_ltks_clear(hdev);
 	hci_remote_oob_data_clear(hdev);
+	__clear_conn_params(hdev);
 	hci_dev_unlock(hdev);
 
 	hci_dev_put(hdev);
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 03/15] Bluetooth: Stop scanning on connection
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

Some LE controllers don't support scanning and creating a connection
at the same time. So, for those controllers, we should stop scanning
in order to establish the connection.

Since we may prematurely stop the discovery procedure in favor of
the connection establishment, we should also cancel hdev->le_scan_
disable delayed work and set the discovery state to DISCOVERY_STOPPED.

This change does a small improvement since it is not mandatory user
stops scanning before connecting anymore. Moreover, this change is
required by upcoming LE auto connection mechanism in order to work
properly with controllers that don't support background scanning and
connection establishment at the same time.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 net/bluetooth/hci_conn.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 9fb7b44..195b78f 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -518,8 +518,11 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
 {
 	struct hci_conn *conn;
 
-	if (status == 0)
+	if (status == 0) {
+		cancel_delayed_work(&hdev->le_scan_disable);
+		hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
 		return;
+	}
 
 	BT_ERR("HCI request failed to create LE connection: status 0x%2.2x",
 	       status);
@@ -543,6 +546,17 @@ done:
 	hci_dev_unlock(hdev);
 }
 
+/* Check if controller supports creating a connection while scanning is
+ * runnning.
+ */
+static bool is_scan_and_conn_supported(struct hci_dev *hdev)
+{
+	u8 mask = BIT(6) | BIT(7);
+
+	/* Return true if both bits are set */
+	return (hdev->le_states[2] & mask) == mask;
+}
+
 static int hci_create_le_conn(struct hci_conn *conn)
 {
 	struct hci_dev *hdev = conn->hdev;
@@ -552,6 +566,20 @@ static int hci_create_le_conn(struct hci_conn *conn)
 
 	hci_req_init(&req, hdev);
 
+	/* If controller is scanning but it doesn't support scanning and
+	 * creating a connection at the same time, we stop scanning.
+	 * Otherwise, LE Create Connection command fails.
+	 */
+	if (test_bit(HCI_LE_SCAN, &hdev->dev_flags) &&
+	    !is_scan_and_conn_supported(hdev)) {
+		struct hci_cp_le_set_scan_enable enable_cp;
+
+		memset(&enable_cp, 0, sizeof(enable_cp));
+		enable_cp.enable = LE_SCAN_DISABLE;
+		hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
+			    &enable_cp);
+	}
+
 	memset(&cp, 0, sizeof(cp));
 	cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
 	cp.scan_window = cpu_to_le16(hdev->le_scan_window);
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 02/15] Bluetooth: Save connection interval parameters in hci_conn
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

This patch creates two new fields in struct hci_conn to save the
minimum and maximum connection interval values used to establish
the connection this object represents.

This change is required in order to know what parameters the
connection is currently using.

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 include/net/bluetooth/hci_core.h | 3 +++
 net/bluetooth/hci_conn.c         | 6 ++++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 8c0ab3d..037a7b5 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -341,6 +341,9 @@ struct hci_conn {
 
 	unsigned int	sent;
 
+	__u16		conn_interval_min;
+	__u16		conn_interval_max;
+
 	struct sk_buff_head data_q;
 	struct list_head chan_list;
 
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index ba5366c..9fb7b44 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -558,8 +558,8 @@ static int hci_create_le_conn(struct hci_conn *conn)
 	bacpy(&cp.peer_addr, &conn->dst);
 	cp.peer_addr_type = conn->dst_type;
 	cp.own_address_type = conn->src_type;
-	cp.conn_interval_min = cpu_to_le16(hdev->le_conn_min_interval);
-	cp.conn_interval_max = cpu_to_le16(hdev->le_conn_max_interval);
+	cp.conn_interval_min = cpu_to_le16(conn->conn_interval_min);
+	cp.conn_interval_max = cpu_to_le16(conn->conn_interval_max);
 	cp.supervision_timeout = __constant_cpu_to_le16(0x002a);
 	cp.min_ce_len = __constant_cpu_to_le16(0x0000);
 	cp.max_ce_len = __constant_cpu_to_le16(0x0000);
@@ -624,6 +624,8 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
 	conn->sec_level = BT_SECURITY_LOW;
 	conn->pending_sec_level = sec_level;
 	conn->auth_type = auth_type;
+	conn->conn_interval_min = hdev->le_conn_min_interval;
+	conn->conn_interval_max = hdev->le_conn_max_interval;
 
 	err = hci_create_le_conn(conn);
 	if (err)
-- 
1.8.4


^ permalink raw reply related

* [RFC v2 01/15] Bluetooth: Refactor hci_disconn_complete_evt
From: Andre Guedes @ 2013-10-29 13:25 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1383053160-10175-1-git-send-email-andre.guedes@openbossa.org>

hci_disconn_complete_evt() logic is more complicated than what it
should be, making it hard to follow and add new features.

So this patch does some code refactoring by handling the error cases
in the beginning of the function and by moving the main flow into the
first level of function scope. No change is done in the event handling
logic itself.

Besides organizing this messy code, this patch makes easier to add
code for handling LE auto connection (which will be added in a further
patch).

Signed-off-by: Andre Guedes <andre.guedes@openbossa.org>
---
 net/bluetooth/hci_event.c | 62 +++++++++++++++++++++++++----------------------
 1 file changed, 33 insertions(+), 29 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5935f74..8b7cd37 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1783,6 +1783,8 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_ev_disconn_complete *ev = (void *) skb->data;
 	struct hci_conn *conn;
+	u8 type;
+	bool send_mgmt_event = false;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
 
@@ -1792,44 +1794,46 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 	if (!conn)
 		goto unlock;
 
-	if (ev->status == 0)
-		conn->state = BT_CLOSED;
-
 	if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
-	    (conn->type == ACL_LINK || conn->type == LE_LINK)) {
-		if (ev->status) {
+	    (conn->type == ACL_LINK || conn->type == LE_LINK))
+		send_mgmt_event = true;
+
+	if (ev->status) {
+		if (send_mgmt_event)
 			mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
 					       conn->dst_type, ev->status);
-		} else {
-			u8 reason = hci_to_mgmt_reason(ev->reason);
-
-			mgmt_device_disconnected(hdev, &conn->dst, conn->type,
-						 conn->dst_type, reason);
-		}
+		return;
 	}
 
-	if (ev->status == 0) {
-		u8 type = conn->type;
+	conn->state = BT_CLOSED;
 
-		if (type == ACL_LINK && conn->flush_key)
-			hci_remove_link_key(hdev, &conn->dst);
-		hci_proto_disconn_cfm(conn, ev->reason);
-		hci_conn_del(conn);
+	if (send_mgmt_event) {
+		u8 reason = hci_to_mgmt_reason(ev->reason);
 
-		/* Re-enable advertising if necessary, since it might
-		 * have been disabled by the connection. From the
-		 * HCI_LE_Set_Advertise_Enable command description in
-		 * the core specification (v4.0):
-		 * "The Controller shall continue advertising until the Host
-		 * issues an LE_Set_Advertise_Enable command with
-		 * Advertising_Enable set to 0x00 (Advertising is disabled)
-		 * or until a connection is created or until the Advertising
-		 * is timed out due to Directed Advertising."
-		 */
-		if (type == LE_LINK)
-			mgmt_reenable_advertising(hdev);
+		mgmt_device_disconnected(hdev, &conn->dst, conn->type,
+					 conn->dst_type, reason);
 	}
 
+	if (conn->type == ACL_LINK && conn->flush_key)
+		hci_remove_link_key(hdev, &conn->dst);
+
+	type = conn->type;
+	hci_proto_disconn_cfm(conn, ev->reason);
+	hci_conn_del(conn);
+
+	/* Re-enable advertising if necessary, since it might
+	 * have been disabled by the connection. From the
+	 * HCI_LE_Set_Advertise_Enable command description in
+	 * the core specification (v4.0):
+	 * "The Controller shall continue advertising until the Host
+	 * issues an LE_Set_Advertise_Enable command with
+	 * Advertising_Enable set to 0x00 (Advertising is disabled)
+	 * or until a connection is created or until the Advertising
+	 * is timed out due to Directed Advertising."
+	 */
+	if (type == LE_LINK)
+		mgmt_reenable_advertising(hdev);
+
 unlock:
 	hci_dev_unlock(hdev);
 }
-- 
1.8.4


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox