Linux bluetooth development
 help / color / mirror / Atom feed
* Re: Bluez 4.101
From: Chan-yeol Park @ 2012-08-16  1:16 UTC (permalink / raw)
  To: John Tobias; +Cc: linux-bluetooth
In-Reply-To: <CACUGKYMjKcZZJsYi-SXCd1C=guWtKP3k=SBVPVe=+MR0R=pwHg@mail.gmail.com>

Hi John

On 08/16/2012 09:26 AM, John Tobias wrote:
> Hi All,
>
> I downloaded the latest Bluez 4.101, compiled and installed on my
> machine. After executing the command (/usr/sbin/bluetoothd -n -d), it
> returned "bluetoothd[15067]: mgmt setup failed: Invalid argument."
> I am just wondering what are the missing key on my build?.
It looks like that your kernel doesn't support mgmt interface.
Which version of kernel do you use?

Regards
chanyeol

^ permalink raw reply

* Bluez 4.101
From: John Tobias @ 2012-08-16  0:26 UTC (permalink / raw)
  To: linux-bluetooth

Hi All,

I downloaded the latest Bluez 4.101, compiled and installed on my
machine. After executing the command (/usr/sbin/bluetoothd -n -d), it
returned "bluetoothd[15067]: mgmt setup failed: Invalid argument."
I am just wondering what are the missing key on my build?.

Regards,

John

^ permalink raw reply

* [PATCH BlueZ 2/2] mgmt: Fix Set SSP command complete
From: Andre Guedes @ 2012-08-15 21:14 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1345065240-9250-1-git-send-email-andre.guedes@openbossa.org>

Once we get a Set SSP command complete event, we should update
current_settings from the controller_info. Otherwise, features
which depend on that will not work properly.
---
 src/mgmt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/mgmt.c b/src/mgmt.c
index fbd2a6b..94b2a04 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -1385,7 +1385,7 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
 		mgmt_new_settings(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_SET_SSP:
-		DBG("set_ssp complete");
+		mgmt_new_settings(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_SET_LE:
 		mgmt_new_settings(sk, index, ev->data, len);
-- 
1.7.11.4


^ permalink raw reply related

* [PATCH BlueZ 1/2] mgmt: Fix Set LE command complete
From: Andre Guedes @ 2012-08-15 21:13 UTC (permalink / raw)
  To: linux-bluetooth

Once we get a Set LE command complete event, we should update
current_settings from the controller_info. Otherwise, features
which depend on that, such as device discovery, will not work
properly.
---
 src/mgmt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/mgmt.c b/src/mgmt.c
index b3ae776..fbd2a6b 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -1388,7 +1388,7 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
 		DBG("set_ssp complete");
 		break;
 	case MGMT_OP_SET_LE:
-		DBG("set_le complete");
+		mgmt_new_settings(sk, index, ev->data, len);
 		break;
 	case MGMT_OP_ADD_UUID:
 		mgmt_add_uuid_complete(sk, index, ev->data, len);
-- 
1.7.11.4


^ permalink raw reply related

* Re: gstreamer a2dpSource plugin
From: alistair.rodger @ 2012-08-15 20:28 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <CABBYNZJTkSf1BFZYge9R5WX7m79=hkDfaENh201EygSdck_yyQ@mail.gmail.com>

I am trying to stream_from_  the device to a local sink.  I am therefore looking for something like;

gst-launch alsasrc device=bluetooth ! sbcdec ! .....
or

gst-launch a2dpsource transport=/org/bluez/{PID}/hci0/dev_AA_BB_CC_DD_EE_FF/fd0 ! sbcdec ! ...

preferably the second option as this would use SBC not PCM.

But to clarify, I have been asked to investigate this as part of a product we are developing.  So I am trying to understand the approach we should take.  As an embedded device we cannot support PulseAudio but instead have been using gstreamer.  I can stream_from_  our device using gstreamer but, I understand, the only way to stream to a device, using the higher quality a2dp sbc codec, is using pulse audio.

There are examples on the web using "gst-launch alsasource device=bluetooth ! ..." but I believe this has been deprecated and can only support the SCO headset profile "low" quality audio.

So what I am trying to determine is;

1) Is there a gstreamer source plugin which would take the audio out of the bluetooth stack and pipe it to the "sbcdec" plugin, from which I can pipe it to something like "alsasink"?
2) is it possible to stream the higher quality audio over alsasrc, or is alsa fundamentally only PCM ?
3) Is our only option to create or commission a gstreamer plugin?  If so what steps should we take to pursue its creation.

Sincerely,
alistair


^ permalink raw reply

* Re: [RFCv0 14/21] Bluetooth: Handle physical link completion
From: Mat Martineau @ 2012-08-15 16:56 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo, pkrystad
In-Reply-To: <20120815135105.GA3555@aemeltch-MOBL1>


Andrei -

On Wed, 15 Aug 2012, Andrei Emeltchenko wrote:

> Hi Mat,
>
> On Wed, Jul 25, 2012 at 04:51:06PM -0700, Mat Martineau wrote:
>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>> ---
>>  net/bluetooth/l2cap_core.c | 147 +++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 147 insertions(+)
>>
>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> index d981d87..7e253ce 100644
>> --- a/net/bluetooth/l2cap_core.c
>> +++ b/net/bluetooth/l2cap_core.c
>> @@ -975,6 +975,19 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan)
>>  	l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
>>  }
>>
>> +static void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 chan_id)
>> +{
>> +	struct l2cap_create_chan_req req;
>> +	req.scid = cpu_to_le16(chan->scid);
>> +	req.psm  = chan->psm;
>> +	req.amp_id = chan_id;
>> +
>> +	chan->ident = l2cap_get_ident(chan->conn);
>> +
>> +	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ,
>> +		       sizeof(req), &req);
>> +}
>> +
>>  static void l2cap_move_setup(struct l2cap_chan *chan)
>>  {
>>  	struct sk_buff *skb;
>> @@ -4119,6 +4132,24 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
>>  	return 0;
>>  }
>>
>> +static void l2cap_send_move_chan_req(struct l2cap_chan *chan, u8 dest_amp_id)
>> +{
>> +	struct l2cap_move_chan_req req;
>> +	u8 ident;
>> +
>> +	BT_DBG("chan %p, dest_amp_id %d", chan, dest_amp_id);
>> +
>> +	ident = l2cap_get_ident(chan->conn);
>> +	if (chan)
>
> I think that the check is not needed otherwise you crash at referencing
> chan->scid below.

Or at the line above.  This check was added before everything had been 
moved from l2cap_pi to l2cap_chan, and is no longer relevant.

>
>> +		chan->ident = ident;
>> +
>> +	req.icid = cpu_to_le16(chan->scid);
>> +	req.dest_amp_id = dest_amp_id;
>> +
>> +	l2cap_send_cmd(chan->conn, ident, L2CAP_MOVE_CHAN_REQ, sizeof(req),
>> +		       &req);
>> +}
>> +
>>  static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
>>  				     u16 icid, u16 result)
>>  {
>> @@ -4284,6 +4315,122 @@ static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
>>  	}
>>  }
>>
>> +void l2cap_physical_cfm(struct l2cap_chan *chan, int result, u8 local_id,
>> +			u8 remote_id)
>> +{
>> +	BT_DBG("chan %p, result %d, local_id %d, remote_id %d", chan, result,
>> +	       local_id, remote_id);
>> +
>> +	l2cap_chan_lock(chan);
>> +
>> +	if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) {
>> +		l2cap_chan_unlock(chan);
>> +		return;
>> +	}
>> +
>> +	if (chan->state != BT_CONNECTED) {
>> +		if (!test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
>> +			struct l2cap_conn_rsp rsp;
>> +			char buf[128];
>> +			rsp.scid = cpu_to_le16(chan->dcid);
>> +			rsp.dcid = cpu_to_le16(chan->scid);
>> +
>> +			/* Incoming channel on AMP */
>> +			if (result == L2CAP_CR_SUCCESS) {
>> +				/* Send successful response */
>> +				rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
>> +				rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
>> +			} else {
>> +				/* Send negative response */
>> +				rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM);
>> +				rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
>> +			}
>> +
>> +			l2cap_send_cmd(chan->conn, chan->ident,
>> +				       L2CAP_CREATE_CHAN_RSP,
>> +				       sizeof(rsp), &rsp);
>> +
>> +			if (result == L2CAP_CR_SUCCESS) {
>> +				__l2cap_state_change(chan, BT_CONFIG);
>> +				set_bit(CONF_REQ_SENT, &chan->conf_state);
>> +				l2cap_send_cmd(chan->conn,
>> +					       l2cap_get_ident(chan->conn),
>> +					       L2CAP_CONF_REQ,
>> +					       l2cap_build_conf_req(chan, buf),
>> +					       buf);
>> +				chan->num_conf_req++;
>> +			}
>> +		} else {
>> +			/* Outgoing channel on AMP */
>> +			if (result == L2CAP_CR_SUCCESS) {
>> +				chan->chan_id = local_id;
>> +				l2cap_send_create_chan_req(chan, remote_id);
>> +			} else {
>> +				/* Revert to BR/EDR connect */
>> +				l2cap_send_conn_req(chan);
>> +			}
>> +		}
>> +	} else if (result == L2CAP_MR_SUCCESS &&
>> +		   chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
>> +		l2cap_move_setup(chan);
>> +		chan->move_id = local_id;
>> +		chan->move_state = L2CAP_MOVE_WAIT_RSP;
>> +
>> +		l2cap_send_move_chan_req(chan, remote_id);
>> +		__set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
>> +	} else if (result == L2CAP_MR_SUCCESS &&
>> +		   chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
>> +		struct hci_chan *hchan = NULL;
>> +
>> +		/* Placeholder - get hci_chan for logical link */
>> +
>> +		if (hchan) {
>> +			if (hchan->state == BT_CONNECTED) {
>> +				/* Logical link is ready to go */
>> +				chan->hs_hcon = hchan->conn;
>> +				chan->hs_hcon->l2cap_data = chan->conn;
>> +				chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
>> +				l2cap_send_move_chan_rsp(chan->conn,
>> +							 chan->move_cmd_ident,
>> +							 chan->dcid,
>> +							 L2CAP_MR_SUCCESS);
>> +
>> +				l2cap_logical_cfm(chan, hchan,
>> +						  L2CAP_MR_SUCCESS);
>> +			} else {
>> +				/* Wait for logical link to be ready */
>> +				chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM;
>> +			}
>> +		} else {
>> +			/* Logical link not available */
>> +			l2cap_send_move_chan_rsp(chan->conn,
>> +						 chan->move_cmd_ident,
>> +						 chan->dcid,
>> +						 L2CAP_MR_NOT_ALLOWED);
>> +		}
>> +	} else {
>> +		if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
>> +			u8 rsp_result;
>> +			if (result == -EINVAL)
>> +				rsp_result = L2CAP_MR_BAD_ID;
>> +			else
>> +				rsp_result = L2CAP_MR_NOT_ALLOWED;
>> +
>> +			l2cap_send_move_chan_rsp(chan->conn,
>> +						 chan->move_cmd_ident,
>> +						 chan->dcid, rsp_result);
>> +		}
>> +
>> +		chan->move_role = L2CAP_MOVE_ROLE_NONE;
>> +		chan->move_state = L2CAP_MOVE_STABLE;
>> +
>> +		/* Restart data transmission */
>> +		l2cap_ertm_send(chan);
>> +	}
>> +
>> +	l2cap_chan_unlock(chan);
>> +}
>
> I feel that this function is too big. Maybe we could split channel move
> and channel create operations?

Sure, the "if (chan->state != BT_CONNECTED)" clause would be clearer 
in a channel create function, and the other clauses can go in a 
channel move function.


--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

^ permalink raw reply

* Re: [PATCH v5 8/8] Added /proc/net/sco via bt_procfs_init()
From: Jan Engelhardt @ 2012-08-15 15:22 UTC (permalink / raw)
  To: Gustavo Padovan
  Cc: Masatake YAMATO, andrei.emeltchenko.news, linux-kernel,
	linux-bluetooth
In-Reply-To: <20120726042411.GA3226@joana>

On Thursday 2012-07-26 06:24, Gustavo Padovan wrote:

>Hi Masatake,
>
>* Masatake YAMATO <yamato@redhat.com> [2012-07-26 01:30:12 +0900]:
>
>> Added /proc/net/sco via bt_procfs_init().
>> 
>> Signed-off-by: Masatake YAMATO <yamato@redhat.com>
>> ---
>>  net/bluetooth/sco.c |    9 +++++++++
>>  1 file changed, 9 insertions(+)
>
>All 8 patches have been applied to bluetooth-next. Thanks.

It may have been raised before, but: should not the info be exported 
over netlink rather than the oldfashioned and overabused procfs?

^ permalink raw reply

* [PATCH BlueZ v2 14/14] core: Re-connect for ECONNRESET or ECONNABORTED
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch keeps scanning and re-connections active if the disconnection
reason is ECONNRESET(Remote Initiated Disconnection).

Re-connection is a behaviour determined by Profiles or by the upper
layer(user actions). For instance, HoG requires re-connection always
active, no matter if the previous disconnection reason was page timeout
or remote initiated disconnection (ECONNRESET). Some devices disconnects
after some idle time, connectable advertises are sent by the peripheral
when commanded by the user(eg: key pressed). Disconnection can be also
triggered by the local host (ECONNABORTED) using command line tools or
Disconnect method in the Device interface.

The peripheral dictates the re-connection controlling the connectable
advertises, BlueZ(central) needs to keep the scanning always active to
able to detect the advertises and trigger the connection.
---
 src/device.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/device.c b/src/device.c
index f116fd7..465783e 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1812,10 +1812,18 @@ static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond,
 
 	g_slist_foreach(device->attios, attio_disconnected, NULL);
 
-	if (device->auto_connect == FALSE || err != ETIMEDOUT)
+	if (device->auto_connect == FALSE) {
+		DBG("Automatic connection disabled");
 		goto done;
+	}
 
-	adapter_connect_list_add(device_get_adapter(device), device);
+	/*
+	 * Keep scanning/re-connection active if disconnection reason
+	 * is page timeout, remote user terminated connection or local
+	 * initiated disconnection.
+	 */
+	if (err == ETIMEDOUT || err == ECONNRESET || err == ECONNABORTED)
+		adapter_connect_list_add(device_get_adapter(device), device);
 
 done:
 	attio_cleanup(device);
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 13/14] core: Disable unnecessary auto connections
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Paulo Alcantara
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

From: Paulo Alcantara <paulo.alcantara@openbossa.org>

BlueZ host disconnects the link when encryption fails. ECONNABORTED
error is returned by the kernel when the connection is terminated by the
local host. This scenario commonly happens when authentication fails due
PIN or Key Missing.
---
 src/device.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/device.c b/src/device.c
index 1d40bb8..f116fd7 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1956,6 +1956,9 @@ static void att_error_cb(const GError *gerr, gpointer user_data)
 	struct att_callbacks *attcb = user_data;
 	struct btd_device *device = attcb->user_data;
 
+	if (gerr->code == ECONNABORTED)
+		return;
+
 	if (device->auto_connect == FALSE)
 		return;
 
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 12/14] test: Fix exiting the bus when a discovery session ends
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Vinicius Costa Gomes
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

From: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>

Sometimes we may want that a discovery session to continue existing
for more than a discovery window. For example, testing starting a
pairing while a discovery session is running.
---
 test/test-discovery | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/test/test-discovery b/test/test-discovery
index 269c51c..08dfd0b 100755
--- a/test/test-discovery
+++ b/test/test-discovery
@@ -22,10 +22,6 @@ def device_found(address, properties):
 
 	print()
 
-def property_changed(name, value):
-	if (name == "Discovering" and not value):
-		mainloop.quit()
-
 if __name__ == '__main__':
 	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
@@ -53,10 +49,6 @@ if __name__ == '__main__':
 			dbus_interface = "org.bluez.Adapter",
 					signal_name = "DeviceFound")
 
-	bus.add_signal_receiver(property_changed,
-			dbus_interface = "org.bluez.Adapter",
-					signal_name = "PropertyChanged")
-
 	adapter.StartDiscovery()
 
 	mainloop = GObject.MainLoop()
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 11/14] core: Queue discovery if scanning is active
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch manages BR/EDR inquiry and BLE scanning discovery sessions.
A scanning session is added in the discovery session list when there is
a bonded device which requires re-connection.

bluetoothd decides if interleaved or scanning needs to be executed based
on the queued discovery sessions. Interleaved discovery has higher
priority, scanning only is executed when there is only a scanning
session active.
---
 src/adapter.c | 68 +++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 47 insertions(+), 21 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 4cd8c10..6b31785 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -132,6 +132,7 @@ struct btd_adapter {
 	GSList *devices;		/* Devices structure pointers */
 	GSList *mode_sessions;		/* Request Mode sessions */
 	GSList *disc_sessions;		/* Discovery sessions */
+	struct session_req *scanning_session;
 	GSList *connect_list;		/* Devices to connect when found */
 	GSList *connecting_list;	/* Pending connects */
 	guint discov_id;		/* Discovery timer */
@@ -220,18 +221,19 @@ static struct session_req *create_session(struct btd_adapter *adapter,
 					DBusConnection *conn, DBusMessage *msg,
 					uint8_t mode, GDBusWatchFunction cb)
 {
-	const char *sender = dbus_message_get_sender(msg);
+	const char *sender;
 	struct session_req *req;
 
 	req = g_new0(struct session_req, 1);
 	req->adapter = adapter;
-	req->conn = dbus_connection_ref(conn);
-	req->msg = dbus_message_ref(msg);
 	req->mode = mode;
 
-	if (cb == NULL)
+	if (conn == NULL || cb == NULL || msg == NULL)
 		return session_ref(req);
 
+	req->conn = dbus_connection_ref(conn);
+	req->msg = dbus_message_ref(msg);
+	sender = dbus_message_get_sender(msg);
 	req->owner = g_strdup(sender);
 	req->id = g_dbus_add_disconnect_watch(conn, sender, cb, req, NULL);
 
@@ -443,7 +445,9 @@ static struct session_req *find_session(GSList *list, const char *sender)
 	for (; list; list = list->next) {
 		struct session_req *req = list->data;
 
-		if (g_str_equal(req->owner, sender))
+		/* req->owner may be NULL if the session has been added by the
+		 * daemon itself, so we use g_strcmp0 instead of g_str_equal */
+		if (g_strcmp0(req->owner, sender) == 0)
 			return req;
 	}
 
@@ -518,7 +522,7 @@ static void session_remove(struct session_req *req)
 	struct btd_adapter *adapter = req->adapter;
 
 	/* Ignore set_mode session */
-	if (req->owner == NULL)
+	if (req->owner == NULL && adapter->pending_mode)
 		return;
 
 	DBG("%s session %p with %s deactivated",
@@ -1007,7 +1011,12 @@ static gboolean discovery_cb(gpointer user_data)
 	struct btd_adapter *adapter = user_data;
 
 	adapter->discov_id = 0;
-	mgmt_start_discovery(adapter->dev_id);
+
+	if (adapter->scanning_session &&
+			(g_slist_length(adapter->disc_sessions) == 1))
+		mgmt_start_scanning(adapter->dev_id);
+	else
+		mgmt_start_discovery(adapter->dev_id);
 
 	return FALSE;
 }
@@ -2187,6 +2196,7 @@ const char *btd_adapter_get_name(struct btd_adapter *adapter)
 void adapter_connect_list_add(struct btd_adapter *adapter,
 					struct btd_device *device)
 {
+	struct session_req *req;
 	bdaddr_t bdaddr;
 
 	device_get_address(device, &bdaddr, NULL);
@@ -2201,10 +2211,21 @@ void adapter_connect_list_add(struct btd_adapter *adapter,
 	DBG("%s added to %s's connect_list", device_get_path(device),
 								adapter->name);
 
-	if (adapter->disc_sessions)
+	if (!adapter->up)
 		return;
 
-	mgmt_start_scanning(adapter->dev_id);
+	if (adapter->off_requested)
+		return;
+
+	if (adapter->scanning_session)
+		return;
+
+	if (adapter->disc_sessions == NULL)
+		adapter->discov_id = g_idle_add(discovery_cb, adapter);
+
+	req = create_session(adapter, NULL, NULL, 0, NULL);
+	adapter->disc_sessions = g_slist_append(adapter->disc_sessions, req);
+	adapter->scanning_session = req;
 }
 
 void adapter_connect_list_remove(struct btd_adapter *adapter,
@@ -2217,6 +2238,7 @@ void adapter_connect_list_remove(struct btd_adapter *adapter,
 
 void btd_adapter_start(struct btd_adapter *adapter)
 {
+	struct session_req *req;
 	char address[18];
 	gboolean powered;
 
@@ -2243,8 +2265,15 @@ void btd_adapter_start(struct btd_adapter *adapter)
 
 	info("Adapter %s has been enabled", adapter->path);
 
-	if (g_slist_length(adapter->connect_list))
-		mgmt_start_scanning(adapter->dev_id);
+	if (g_slist_length(adapter->connect_list) == 0 ||
+					adapter->disc_sessions)
+		return;
+
+	req = create_session(adapter, NULL, NULL, 0, NULL);
+	adapter->disc_sessions = g_slist_append(adapter->disc_sessions, req);
+	adapter->scanning_session = req;
+
+	adapter->discov_id = g_idle_add(discovery_cb, adapter);
 }
 
 static void reply_pending_requests(struct btd_adapter *adapter)
@@ -2578,6 +2607,11 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 
 	connect_list_size = g_slist_length(adapter->connect_list);
 
+	if (connect_list_size == 0 && adapter->scanning_session) {
+		session_unref(adapter->scanning_session);
+		adapter->scanning_session = NULL;
+	}
+
 	if (adapter_has_discov_sessions(adapter)) {
 		adapter->discov_id = g_idle_add(discovery_cb, adapter);
 
@@ -2586,14 +2620,6 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 				g_slist_length(adapter->disc_sessions));
 		return;
 	}
-
-	if (connect_list_size) {
-		mgmt_start_scanning(adapter->dev_id);
-
-		DBG("hci%u restarting scanning connect_list size %u",
-				adapter->dev_id, connect_list_size);
-		return;
-	}
 }
 
 static void suspend_discovery(struct btd_adapter *adapter)
@@ -2902,7 +2928,6 @@ static gboolean clean_connecting_state(GIOChannel *io, GIOCondition cond, gpoint
 	struct btd_device *device = user_data;
 	struct btd_adapter *adapter = device_get_adapter(device);
 
-	adapter_connect_list_remove(adapter, device);
 	adapter->connecting_list = g_slist_remove(adapter->connecting_list,
 								device);
 
@@ -2910,7 +2935,7 @@ static gboolean clean_connecting_state(GIOChannel *io, GIOCondition cond, gpoint
 
 	if (!g_slist_length(adapter->connecting_list) &&
 					g_slist_length(adapter->connect_list))
-		mgmt_start_scanning(adapter->dev_id);
+		adapter->discov_id = g_idle_add(discovery_cb, adapter);
 
 	btd_device_unref(device);
 
@@ -3035,6 +3060,7 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
 			goto done;
 
 		device = l->data;
+		adapter_connect_list_remove(adapter, device);
 		l = g_slist_find(adapter->connecting_list, device);
 		if (l)
 			goto done;
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 10/14] core: Remove leftover define
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

---
 src/device.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/device.c b/src/device.c
index 74d3c68..1d40bb8 100644
--- a/src/device.c
+++ b/src/device.c
@@ -67,8 +67,6 @@
 #define DISCONNECT_TIMER	2
 #define DISCOVERY_TIMER		2
 
-#define AUTO_CONNECTION_INTERVAL	5 /* Next connection attempt */
-
 #define APPEARANCE_CHR_UUID 0x2a01
 
 struct btd_disconnect_data {
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 09/14] core: Start LE scanning when a device requests
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch enables the LE scanning when a device requires connection and
there isn't discovery sessions, triggering the General Connection
Establishment Procedure.
---
 src/adapter.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index c3ec714..4cd8c10 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2200,6 +2200,11 @@ void adapter_connect_list_add(struct btd_adapter *adapter,
 	adapter->connect_list = g_slist_append(adapter->connect_list, device);
 	DBG("%s added to %s's connect_list", device_get_path(device),
 								adapter->name);
+
+	if (adapter->disc_sessions)
+		return;
+
+	mgmt_start_scanning(adapter->dev_id);
 }
 
 void adapter_connect_list_remove(struct btd_adapter *adapter,
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 08/14] core: Replace interleaved by LE scanning
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patches replaces the interleaved discovery by LE scanning when LE
re-connection is required.
---
 src/adapter.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 52983ee..c3ec714 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2239,7 +2239,7 @@ void btd_adapter_start(struct btd_adapter *adapter)
 	info("Adapter %s has been enabled", adapter->path);
 
 	if (g_slist_length(adapter->connect_list))
-		mgmt_start_discovery(adapter->dev_id);
+		mgmt_start_scanning(adapter->dev_id);
 }
 
 static void reply_pending_requests(struct btd_adapter *adapter)
@@ -2573,14 +2573,22 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 
 	connect_list_size = g_slist_length(adapter->connect_list);
 
-	if (!adapter_has_discov_sessions(adapter) && !connect_list_size)
+	if (adapter_has_discov_sessions(adapter)) {
+		adapter->discov_id = g_idle_add(discovery_cb, adapter);
+
+		DBG("hci%u restarting discovery: disc_sessions %u",
+				adapter->dev_id,
+				g_slist_length(adapter->disc_sessions));
 		return;
+	}
 
-	DBG("hci%u restarting discovery: disc_sessions %u, connect_list size "
-		"%u", adapter->dev_id, g_slist_length(adapter->disc_sessions),
-							connect_list_size);
+	if (connect_list_size) {
+		mgmt_start_scanning(adapter->dev_id);
 
-	adapter->discov_id = g_idle_add(discovery_cb, adapter);
+		DBG("hci%u restarting scanning connect_list size %u",
+				adapter->dev_id, connect_list_size);
+		return;
+	}
 }
 
 static void suspend_discovery(struct btd_adapter *adapter)
@@ -2897,7 +2905,7 @@ static gboolean clean_connecting_state(GIOChannel *io, GIOCondition cond, gpoint
 
 	if (!g_slist_length(adapter->connecting_list) &&
 					g_slist_length(adapter->connect_list))
-		mgmt_start_discovery(adapter->dev_id);
+		mgmt_start_scanning(adapter->dev_id);
 
 	btd_device_unref(device);
 
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 07/14] mgmt: Add LE scanning callback
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch adds a new callback to allow the adapter to control LE
scanning. The current approach uses the active scanning with default
windows and intervals defined by the core spec without any filtering.
---
 src/mgmt.c | 34 ++++++++++++++++++++++++++++++++++
 src/mgmt.h |  1 +
 2 files changed, 35 insertions(+)

diff --git a/src/mgmt.c b/src/mgmt.c
index 38b102b..7696871 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -1999,6 +1999,40 @@ int mgmt_start_discovery(int index)
 	return 0;
 }
 
+int mgmt_start_scanning(int index)
+{
+	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_start_discovery)];
+	struct mgmt_hdr *hdr = (void *) buf;
+	struct mgmt_cp_start_discovery *cp = (void *) &buf[sizeof(*hdr)];
+	struct controller_info *info = &controllers[index];
+
+	DBG("index %d", index);
+
+	if (!mgmt_low_energy(info->current_settings)) {
+		error("scanning failed: Low Energy not enabled/supported");
+		return -ENOTSUP;
+	}
+
+	info->discov_type = 0;
+	hci_set_bit(BDADDR_LE_PUBLIC, &info->discov_type);
+	hci_set_bit(BDADDR_LE_RANDOM, &info->discov_type);
+
+	memset(buf, 0, sizeof(buf));
+	hdr->opcode = htobs(MGMT_OP_START_DISCOVERY);
+	hdr->len = htobs(sizeof(*cp));
+	hdr->index = htobs(index);
+
+	cp->type = info->discov_type;
+
+	if (write(mgmt_sock, buf, sizeof(buf)) < 0) {
+		int err = -errno;
+		error("failed to write to MGMT socket: %s", strerror(-err));
+		return err;
+	}
+
+	return 0;
+}
+
 int mgmt_stop_discovery(int index)
 {
 	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_start_discovery)];
diff --git a/src/mgmt.h b/src/mgmt.h
index 95245d2..eb7434a 100644
--- a/src/mgmt.h
+++ b/src/mgmt.h
@@ -33,6 +33,7 @@ int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor);
 int mgmt_set_fast_connectable(int index, gboolean enable);
 
 int mgmt_start_discovery(int index);
+int mgmt_start_scanning(int index);
 int mgmt_stop_discovery(int index);
 
 int mgmt_read_clock(int index, bdaddr_t *bdaddr, int which, int timeout,
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 06/14] core: mutually exclude concurrent connections
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

Since controllers don't support more than one ongoing connection
procedure at the same time, new connection attempts needs to yield if
there is an ongoing connection procedure already.
---
 src/adapter.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
 src/device.c  |  4 ++--
 src/device.h  |  2 +-
 3 files changed, 60 insertions(+), 11 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index ea707d3..52983ee 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -133,8 +133,10 @@ struct btd_adapter {
 	GSList *mode_sessions;		/* Request Mode sessions */
 	GSList *disc_sessions;		/* Discovery sessions */
 	GSList *connect_list;		/* Devices to connect when found */
+	GSList *connecting_list;	/* Pending connects */
 	guint discov_id;		/* Discovery timer */
 	gboolean discovering;		/* Discovery active */
+	gboolean connecting;		/* Connect active */
 	gboolean discov_suspended;	/* Discovery suspended */
 	guint auto_timeout_id;		/* Automatic connections timeout */
 	sdp_list_t *services;		/* Services associated to adapter */
@@ -2235,6 +2237,9 @@ void btd_adapter_start(struct btd_adapter *adapter)
 	call_adapter_powered_callbacks(adapter, TRUE);
 
 	info("Adapter %s has been enabled", adapter->path);
+
+	if (g_slist_length(adapter->connect_list))
+		mgmt_start_discovery(adapter->dev_id);
 }
 
 static void reply_pending_requests(struct btd_adapter *adapter)
@@ -2548,6 +2553,7 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 						gboolean discovering)
 {
 	const char *path = adapter->path;
+	guint connect_list_size;
 
 	adapter->discovering = discovering;
 
@@ -2562,11 +2568,17 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 	g_slist_free_full(adapter->oor_devices, dev_info_free);
 	adapter->oor_devices = g_slist_copy(adapter->found_devices);
 
-	if (!adapter_has_discov_sessions(adapter) || adapter->discov_suspended)
+	if (adapter->discov_suspended)
 		return;
 
-	DBG("hci%u restarting discovery, disc_sessions %u", adapter->dev_id,
-					g_slist_length(adapter->disc_sessions));
+	connect_list_size = g_slist_length(adapter->connect_list);
+
+	if (!adapter_has_discov_sessions(adapter) && !connect_list_size)
+		return;
+
+	DBG("hci%u restarting discovery: disc_sessions %u, connect_list size "
+		"%u", adapter->dev_id, g_slist_length(adapter->disc_sessions),
+							connect_list_size);
 
 	adapter->discov_id = g_idle_add(discovery_cb, adapter);
 }
@@ -2872,17 +2884,44 @@ static char *read_stored_data(bdaddr_t *local, bdaddr_t *peer,
 	return textfile_get(filename, key);
 }
 
+static gboolean clean_connecting_state(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+	struct btd_device *device = user_data;
+	struct btd_adapter *adapter = device_get_adapter(device);
+
+	adapter_connect_list_remove(adapter, device);
+	adapter->connecting_list = g_slist_remove(adapter->connecting_list,
+								device);
+
+	adapter->connecting = FALSE;
+
+	if (!g_slist_length(adapter->connecting_list) &&
+					g_slist_length(adapter->connect_list))
+		mgmt_start_discovery(adapter->dev_id);
+
+	btd_device_unref(device);
+
+	return FALSE;
+}
+
 static gboolean connect_pending_cb(gpointer user_data)
 {
 	struct btd_device *device = user_data;
 	struct btd_adapter *adapter = device_get_adapter(device);
+	GIOChannel *io;
 
 	/* in the future we may want to check here if the controller supports
 	 * scanning and connecting at the same time */
 	if (adapter->discovering)
 		return TRUE;
 
-	device_att_connect(device);
+	if (adapter->connecting)
+		return TRUE;
+
+	adapter->connecting = TRUE;
+	io = device_att_connect(device);
+	g_io_add_watch(io, G_IO_OUT | G_IO_ERR, clean_connecting_state,
+						btd_device_ref(device));
 
 	return FALSE;
 }
@@ -2975,12 +3014,22 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
 
 	if (bdaddr_type == BDADDR_LE_PUBLIC ||
 					bdaddr_type == BDADDR_LE_RANDOM) {
+		struct btd_device *device;
+
 		l = g_slist_find_custom(adapter->connect_list, bdaddr,
 					(GCompareFunc) device_bdaddr_cmp);
-		if (l) {
-			g_idle_add(connect_pending_cb, l->data);
-			stop_discovery(adapter);
-		}
+		if (!l)
+			goto done;
+
+		device = l->data;
+		l = g_slist_find(adapter->connecting_list, device);
+		if (l)
+			goto done;
+
+		g_idle_add(connect_pending_cb, device);
+		adapter->connecting_list = g_slist_append(
+					adapter->connecting_list, device);
+		stop_discovery(adapter);
 	}
 
 done:
diff --git a/src/device.c b/src/device.c
index e677976..74d3c68 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1976,7 +1976,7 @@ static void att_success_cb(gpointer user_data)
 	g_slist_foreach(device->attios, attio_connected, device->attrib);
 }
 
-gboolean device_att_connect(gpointer user_data)
+GIOChannel *device_att_connect(gpointer user_data)
 {
 	struct btd_device *device = user_data;
 	struct btd_adapter *adapter = device->adapter;
@@ -2024,7 +2024,7 @@ gboolean device_att_connect(gpointer user_data)
 
 	device->att_io = io;
 
-	return FALSE;
+	return io;
 }
 
 static void att_browse_error_cb(const GError *gerr, gpointer user_data)
diff --git a/src/device.h b/src/device.h
index 9b7df1c..5f51745 100644
--- a/src/device.h
+++ b/src/device.h
@@ -127,4 +127,4 @@ int device_unblock(DBusConnection *conn, struct btd_device *device,
 void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src,
 			uint16_t vendor_id, uint16_t product_id,
 			uint16_t product_ver);
-gboolean device_att_connect(gpointer user_data);
+GIOChannel *device_att_connect(gpointer user_data);
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 05/14] core: use adapter connect list for LE connections
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

When a connection is needed for a LE device it is added to the adapter
connect list instead of directly connecting the ATT io channel.
---
 src/adapter.c |  2 +-
 src/device.c  | 43 +++++++++++--------------------------------
 src/device.h  |  1 +
 3 files changed, 13 insertions(+), 33 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 080b03f..ea707d3 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2882,7 +2882,7 @@ static gboolean connect_pending_cb(gpointer user_data)
 	if (adapter->discovering)
 		return TRUE;
 
-	/* TODO: call device connect callback */
+	device_att_connect(device);
 
 	return FALSE;
 }
diff --git a/src/device.c b/src/device.c
index 24b9065..e677976 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1798,15 +1798,6 @@ static void attio_disconnected(gpointer data, gpointer user_data)
 		attio->dcfunc(attio->user_data);
 }
 
-static void att_connect_dispatched(gpointer user_data)
-{
-	struct btd_device *device = user_data;
-
-	device->auto_id = 0;
-}
-
-static gboolean att_connect(gpointer user_data);
-
 static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
@@ -1826,10 +1817,7 @@ static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond,
 	if (device->auto_connect == FALSE || err != ETIMEDOUT)
 		goto done;
 
-	device->auto_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE,
-						AUTO_CONNECTION_INTERVAL,
-						att_connect, device,
-						att_connect_dispatched);
+	adapter_connect_list_add(device_get_adapter(device), device);
 
 done:
 	attio_cleanup(device);
@@ -1973,11 +1961,7 @@ static void att_error_cb(const GError *gerr, gpointer user_data)
 	if (device->auto_connect == FALSE)
 		return;
 
-	device->auto_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE,
-						AUTO_CONNECTION_INTERVAL,
-						att_connect, device,
-						att_connect_dispatched);
-
+	adapter_connect_list_add(device_get_adapter(device), device);
 	DBG("Enabling automatic connections");
 }
 
@@ -1992,7 +1976,7 @@ static void att_success_cb(gpointer user_data)
 	g_slist_foreach(device->attios, attio_connected, device->attrib);
 }
 
-static gboolean att_connect(gpointer user_data)
+gboolean device_att_connect(gpointer user_data)
 {
 	struct btd_device *device = user_data;
 	struct btd_adapter *adapter = device->adapter;
@@ -2262,6 +2246,9 @@ void device_set_temporary(struct btd_device *device, gboolean temporary)
 
 	DBG("temporary %d", temporary);
 
+	if (temporary)
+		adapter_connect_list_remove(device_get_adapter(device), device);
+
 	device->temporary = temporary;
 }
 
@@ -2277,6 +2264,7 @@ void device_set_bonded(struct btd_device *device, gboolean bonded)
 
 void device_set_auto_connect(struct btd_device *device, gboolean enable)
 {
+	struct btd_adapter *adapter = device_get_adapter(device);
 	char addr[18];
 
 	if (!device)
@@ -2290,15 +2278,10 @@ void device_set_auto_connect(struct btd_device *device, gboolean enable)
 
 	/* Disabling auto connect */
 	if (enable == FALSE) {
-		if (device->auto_id)
-			g_source_remove(device->auto_id);
+		adapter_connect_list_remove(adapter, device);
 		return;
 	}
 
-	/* Enabling auto connect */
-	if (device->auto_id != 0)
-		return;
-
 	if (device->attrib) {
 		DBG("Already connected");
 		return;
@@ -2307,9 +2290,8 @@ void device_set_auto_connect(struct btd_device *device, gboolean enable)
 	if (device->attios == NULL && device->attios_offline == NULL)
 		return;
 
-	device->auto_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
-						att_connect, device,
-						att_connect_dispatched);
+	/* Enabling auto connect */
+	adapter_connect_list_add(adapter, device);
 }
 
 static gboolean start_discovery(gpointer user_data)
@@ -3091,10 +3073,7 @@ guint btd_device_add_attio_callback(struct btd_device *device,
 
 	device->attios = g_slist_append(device->attios, attio);
 
-	if (device->auto_id == 0)
-		device->auto_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
-						att_connect, device,
-						att_connect_dispatched);
+	adapter_connect_list_add(device_get_adapter(device), device);
 
 	return attio->id;
 }
diff --git a/src/device.h b/src/device.h
index 2b2e6d8..9b7df1c 100644
--- a/src/device.h
+++ b/src/device.h
@@ -127,3 +127,4 @@ int device_unblock(DBusConnection *conn, struct btd_device *device,
 void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src,
 			uint16_t vendor_id, uint16_t product_id,
 			uint16_t product_ver);
+gboolean device_att_connect(gpointer user_data);
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 04/14] core: Add a list of LE devices to connect
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

This commit creates a per-adapter list of LE devices to connect when a
advertising from them is seen during a scan.
---
 src/adapter.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/adapter.h |  3 +++
 2 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/src/adapter.c b/src/adapter.c
index 2ceac5c..080b03f 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -132,6 +132,7 @@ struct btd_adapter {
 	GSList *devices;		/* Devices structure pointers */
 	GSList *mode_sessions;		/* Request Mode sessions */
 	GSList *disc_sessions;		/* Discovery sessions */
+	GSList *connect_list;		/* Devices to connect when found */
 	guint discov_id;		/* Discovery timer */
 	gboolean discovering;		/* Discovery active */
 	gboolean discov_suspended;	/* Discovery suspended */
@@ -2181,6 +2182,32 @@ const char *btd_adapter_get_name(struct btd_adapter *adapter)
 	return adapter->name;
 }
 
+void adapter_connect_list_add(struct btd_adapter *adapter,
+					struct btd_device *device)
+{
+	bdaddr_t bdaddr;
+
+	device_get_address(device, &bdaddr, NULL);
+	if (g_slist_find_custom(adapter->connect_list, &bdaddr,
+					(GCompareFunc) device_bdaddr_cmp)) {
+		DBG("trying to add device %s which is already in the connect "
+				"list, ignoring", device_get_path(device));
+		return;
+	}
+
+	adapter->connect_list = g_slist_append(adapter->connect_list, device);
+	DBG("%s added to %s's connect_list", device_get_path(device),
+								adapter->name);
+}
+
+void adapter_connect_list_remove(struct btd_adapter *adapter,
+					struct btd_device *device)
+{
+	adapter->connect_list = g_slist_remove(adapter->connect_list, device);
+	DBG("%s removed from %s's connect_list", device_get_path(device),
+								adapter->name);
+}
+
 void btd_adapter_start(struct btd_adapter *adapter)
 {
 	char address[18];
@@ -2845,6 +2872,21 @@ static char *read_stored_data(bdaddr_t *local, bdaddr_t *peer,
 	return textfile_get(filename, key);
 }
 
+static gboolean connect_pending_cb(gpointer user_data)
+{
+	struct btd_device *device = user_data;
+	struct btd_adapter *adapter = device_get_adapter(device);
+
+	/* in the future we may want to check here if the controller supports
+	 * scanning and connecting at the same time */
+	if (adapter->discovering)
+		return TRUE;
+
+	/* TODO: call device connect callback */
+
+	return FALSE;
+}
+
 void adapter_update_found_devices(struct btd_adapter *adapter,
 					bdaddr_t *bdaddr, uint8_t bdaddr_type,
 					int8_t rssi, uint8_t confirm_name,
@@ -2856,6 +2898,7 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
 	gboolean legacy, name_known;
 	uint32_t dev_class;
 	int err;
+	GSList *l;
 
 	memset(&eir_data, 0, sizeof(eir_data));
 	err = eir_parse(&eir_data, data, data_len);
@@ -2878,7 +2921,7 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
 								eir_data.name);
 
 	dev = adapter_search_found_devices(adapter, bdaddr);
-	if (dev) {
+	if (dev && dev->bdaddr_type == BDADDR_BREDR) {
 		adapter->oor_devices = g_slist_remove(adapter->oor_devices,
 							dev);
 
@@ -2930,6 +2973,16 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
 
 	adapter->found_devices = g_slist_prepend(adapter->found_devices, dev);
 
+	if (bdaddr_type == BDADDR_LE_PUBLIC ||
+					bdaddr_type == BDADDR_LE_RANDOM) {
+		l = g_slist_find_custom(adapter->connect_list, bdaddr,
+					(GCompareFunc) device_bdaddr_cmp);
+		if (l) {
+			g_idle_add(connect_pending_cb, l->data);
+			stop_discovery(adapter);
+		}
+	}
+
 done:
 	dev->rssi = rssi;
 
diff --git a/src/adapter.h b/src/adapter.h
index 5a0247e..32f3a6d 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -232,3 +232,6 @@ int btd_adapter_gatt_server_start(struct btd_adapter *adapter);
 void btd_adapter_gatt_server_stop(struct btd_adapter *adapter);
 
 int btd_adapter_ssp_enabled(struct btd_adapter *adapter);
+
+void adapter_connect_list_add(struct btd_adapter *adapter, struct btd_device *device);
+void adapter_connect_list_remove(struct btd_adapter *adapter, struct btd_device *device);
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 03/14] core: add compare function for bdaddr in a struct btd_device
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

This is a utility function similar to device_address_cmp but comparing
bdaddr instead of the string representing the address. This way is
possible to avoid allocating two buffers to temporarily hold the
strings, two sprintf() calls to generate the strings from the bdaddr
arrays, and a string comparison, substituting all of it for one memcmp()
call.
---
 src/device.c | 5 +++++
 src/device.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/src/device.c b/src/device.c
index dad9c79..24b9065 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1228,6 +1228,11 @@ gint device_address_cmp(struct btd_device *device, const gchar *address)
 	return strcasecmp(addr, address);
 }
 
+gint device_bdaddr_cmp(struct btd_device *device, bdaddr_t *bdaddr)
+{
+	return bacmp(&device->bdaddr, bdaddr);
+}
+
 static gboolean record_has_uuid(const sdp_record_t *rec,
 				const char *profile_uuid)
 {
diff --git a/src/device.h b/src/device.h
index 26e17f7..2b2e6d8 100644
--- a/src/device.h
+++ b/src/device.h
@@ -45,6 +45,7 @@ uint16_t btd_device_get_product(struct btd_device *device);
 uint16_t btd_device_get_version(struct btd_device *device);
 void device_remove(struct btd_device *device, gboolean remove_stored);
 gint device_address_cmp(struct btd_device *device, const gchar *address);
+gint device_bdaddr_cmp(struct btd_device *device, bdaddr_t *bdaddr);
 int device_browse_primary(struct btd_device *device, DBusConnection *conn,
 				DBusMessage *msg, gboolean secure);
 int device_browse_sdp(struct btd_device *device, DBusConnection *conn,
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 02/14] mgmt: print error message when start_discovery fails
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

If we fail to communicate with the MGMT socket is better to print the
error message on the mgmtops plugin, where it really happened, instead
of leaving this job to its users.
---
 src/adapter.c | 6 +-----
 src/mgmt.c    | 7 +++++--
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 8709a91..2ceac5c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1002,13 +1002,9 @@ struct btd_device *adapter_get_device(DBusConnection *conn,
 static gboolean discovery_cb(gpointer user_data)
 {
 	struct btd_adapter *adapter = user_data;
-	int err;
 
 	adapter->discov_id = 0;
-
-	err = mgmt_start_discovery(adapter->dev_id);
-	if (err < 0)
-		error("start_discovery: %s (%d)", strerror(-err), -err);
+	mgmt_start_discovery(adapter->dev_id);
 
 	return FALSE;
 }
diff --git a/src/mgmt.c b/src/mgmt.c
index b3ae776..38b102b 100644
--- a/src/mgmt.c
+++ b/src/mgmt.c
@@ -1990,8 +1990,11 @@ int mgmt_start_discovery(int index)
 
 	cp->type = info->discov_type;
 
-	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-		return -errno;
+	if (write(mgmt_sock, buf, sizeof(buf)) < 0) {
+		int err = -errno;
+		error("failed to write to MGMT socket: %s", strerror(-err));
+		return err;
+	}
 
 	return 0;
 }
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 01/14] core: Control connections based on adapter state
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1345042253-15053-1-git-send-email-jprvita@openbossa.org>

From: Claudio Takahasi <claudio.takahasi@openbossa.org>

This patch disable automatic ATTIO connections when the adapter is
powered down and enable automatic connection when the adapter is powered
on.
---
 src/adapter.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index e6b5559..8709a91 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2098,6 +2098,14 @@ static int get_pairable_timeout(const char *src)
 	return main_opts.pairto;
 }
 
+static void set_auto_connect(gpointer data, gpointer user_data)
+{
+	struct btd_device *device = data;
+	gboolean enable = GPOINTER_TO_INT(user_data);
+
+	device_set_auto_connect(device, enable);
+}
+
 static void call_adapter_powered_callbacks(struct btd_adapter *adapter,
 						gboolean powered)
 {
@@ -2107,7 +2115,10 @@ static void call_adapter_powered_callbacks(struct btd_adapter *adapter,
 		btd_adapter_powered_cb cb = l->data;
 
 		cb(adapter, powered);
-       }
+	}
+
+	g_slist_foreach(adapter->devices, set_auto_connect,
+						GINT_TO_POINTER(powered));
 }
 
 static void emit_device_disappeared(gpointer data, gpointer user_data)
@@ -3318,15 +3329,10 @@ static gboolean disable_auto(gpointer user_data)
 	return FALSE;
 }
 
-static void set_auto_connect(gpointer data, gpointer user_data)
-{
-	struct btd_device *device = data;
-
-	device_set_auto_connect(device, TRUE);
-}
-
 void btd_adapter_enable_auto_connect(struct btd_adapter *adapter)
 {
+	gboolean enable = TRUE;
+
 	if (!adapter->up)
 		return;
 
@@ -3335,7 +3341,8 @@ void btd_adapter_enable_auto_connect(struct btd_adapter *adapter)
 	if (adapter->auto_timeout_id)
 		return;
 
-	g_slist_foreach(adapter->devices, set_auto_connect, NULL);
+	g_slist_foreach(adapter->devices, set_auto_connect,
+						GINT_TO_POINTER(enable));
 
 	adapter->auto_timeout_id = g_timeout_add_seconds(main_opts.autoto,
 						disable_auto, adapter);
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH BlueZ v2 00/14] LE General Connection Establishment procedure
From: João Paulo Rechi Vita @ 2012-08-15 14:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: João Paulo Rechi Vita

This series implement the LE General Connection Establishment procedure
for LE connections.

If there are LE bonded devices marked for auto connection they are added
to a connect_list on the adapter. When there is any device on this list
scan is performed continuously. When a device is found the connect_list
is checked. If that device is on the list scan is stopped and a
connection attempt is made to that device.

If any client tries to perform discovery and the scan for the General
Connection Establishment procedure is active, the discovery request is
queued and performed right after the GCEP scan session finishes.

This series changes quite a lot the LE connection logic, but we've been
testing and using this code at INdT for about 4 weeks. Any comments and
more testing are appreciated.

Claudio Takahasi (7):
  core: Control connections based on adapter state
  mgmt: Add LE scanning callback
  core: Replace interleaved by LE scanning
  core: Start LE scanning when a device requests
  core: Remove leftover define
  core: Queue discovery if scanning is active
  core: Re-connect for ECONNRESET or ECONNABORTED

João Paulo Rechi Vita (5):
  mgmt: print error message when start_discovery fails
  core: add compare function for bdaddr in a struct btd_device
  core: Add a list of LE devices to connect
  core: use adapter connect list for LE connections
  core: mutually exclude concurrent connections

Paulo Alcantara (1):
  core: Disable unnecessary auto connections

Vinicius Costa Gomes (1):
  test: Fix exiting the bus when a discovery session ends

 src/adapter.c       | 192 +++++++++++++++++++++++++++++++++++++++++++++-------
 src/adapter.h       |   3 +
 src/device.c        |  65 ++++++++----------
 src/device.h        |   2 +
 src/mgmt.c          |  41 ++++++++++-
 src/mgmt.h          |   1 +
 test/test-discovery |   8 ---
 7 files changed, 242 insertions(+), 70 deletions(-)

-- 
1.7.11.2


^ permalink raw reply

* [PATCH BlueZ v0 10/10] gap: Don't store Appearance if value is "unknown"
From: Claudio Takahasi @ 2012-08-15 14:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1345040407-17767-1-git-send-email-claudio.takahasi@openbossa.org>

The Core SPEC is not clear regarding the behaviour or the Appearance
characteristic. According to the SPEC, the Appearance characteristic
should be readable without authentication or authorization. This patch
will keep the Appearance characteristic value refresh (read) on every
re-connection if the value is 0x0000.
---
 profiles/gap/gap.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/profiles/gap/gap.c b/profiles/gap/gap.c
index ff5715b..596d0b9 100644
--- a/profiles/gap/gap.c
+++ b/profiles/gap/gap.c
@@ -98,6 +98,9 @@ static void appearance_cb(guint8 status, const guint8 *pdu, guint16 plen,
 
 	device_set_appearance(gap->device, app);
 
+	if (app == 0x0000)
+		goto done;
+
 	adapter_get_address(device_get_adapter(gap->device), &src);
 	device_get_address(gap->device, &dst, &type);
 
-- 
1.7.8.6


^ permalink raw reply related

* [PATCH BlueZ v0 09/10] gap: Map Appearance value 0x0000 to unknown
From: Claudio Takahasi @ 2012-08-15 14:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1345040407-17767-1-git-send-email-claudio.takahasi@openbossa.org>

According to Bluetooth SIG Assigned numbers, Appearance characteristic
value 0x0000 is designated to "unknown".
---
 src/dbus-common.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/src/dbus-common.c b/src/dbus-common.c
index 7e1bc94..fb55027 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -247,6 +247,8 @@ const char *class_to_icon(uint32_t class)
 const char *gap_appearance_to_icon(uint16_t appearance)
 {
 	switch ((appearance & 0xffc0) >> 6) {
+	case 0x00:
+		return "unknown";
 	case 0x01:
 		return "phone";
 	case 0x02:
-- 
1.7.8.6


^ permalink raw reply related

* [PATCH BlueZ v0 08/10] core: PropertyChanged signal for Icon/Appearance
From: Claudio Takahasi @ 2012-08-15 14:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1345040407-17767-1-git-send-email-claudio.takahasi@openbossa.org>

This patch emits the PropertyChanged signal in the Device hierarchy when
the remote device Appearance characteristic is read. In general
Appearance is a static value, if the device doesn't expose the
Appearance value in the advertising data, the GAP plugin should read the
value using GATT read procedure.
---
 src/device.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/src/device.c b/src/device.c
index f14ea82..d052dd0 100644
--- a/src/device.c
+++ b/src/device.c
@@ -3001,9 +3001,14 @@ void device_set_class(struct btd_device *device, uint32_t value)
 void device_set_appearance(struct btd_device *device, uint16_t value)
 {
 	DBusConnection *conn = get_dbus_connection();
+	const char *icon = gap_appearance_to_icon(value);
 
 	emit_property_changed(conn, device->path, DEVICE_INTERFACE,
 				"Appearance", DBUS_TYPE_UINT16, &value);
+
+	if (icon)
+		emit_property_changed(conn, device->path, DEVICE_INTERFACE,
+					"Icon", DBUS_TYPE_STRING, &icon);
 }
 
 static gboolean notify_attios(gpointer user_data)
-- 
1.7.8.6


^ 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