Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH] android/tester: Add missing hook removal
From: Jakub Tyszkowski @ 2014-10-17 12:10 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Tyszkowski

Missing hook removal was resulting in memory leak:
936 bytes in 39 blocks are definitely lost in loss record 42 of 45
==15026==    at 0x4C2AB80: malloc (in
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==15026==    by 0x407D60: btdev_add_hook (btdev.c:3226)
==15026==    by 0x40EB75: read_info_callback (tester-main.c:364)
==15026==    by 0x4142B5: request_complete (mgmt.c:245)
==15026==    by 0x41441A: can_read_data (mgmt.c:349)
==15026==    by 0x41663C: read_callback (io-glib.c:170)
==15026==    by 0x5083CE4: g_main_context_dispatch (in
/lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==15026==    by 0x5084047: ??? (in
/lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==15026==    by 0x5084309: g_main_loop_run (in
/lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==15026==    by 0x4162D0: tester_run (tester.c:815)
==15026==    by 0x40263E: main (tester-main.c:2716)
---
 android/tester-main.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/android/tester-main.c b/android/tester-main.c
index a804f11..fc1de06 100644
--- a/android/tester-main.c
+++ b/android/tester-main.c
@@ -212,6 +212,9 @@ static void test_post_teardown(const void *test_data)
 {
 	struct test_data *data = tester_get_data();
 
+	/* remove hook for encryption change */
+	hciemu_del_hook(data->hciemu, HCIEMU_HOOK_POST_EVT, 0x08);
+
 	hciemu_unref(data->hciemu);
 	data->hciemu = NULL;
 
-- 
1.9.1


^ permalink raw reply related

* Locking issue when running out of credits in 6lowpan connection
From: Jukka Rissanen @ 2014-10-17 12:37 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Johan Hedberg, Marcel Holtmann

Hi,

I have seen the deadlock warnings from lockdep when pushing lot of data
through a 6lowpan link. I was converting the read/write locks in 6lowpan
to use RCU and it helped the situation slightly as I see the lockdep
warning less now. I will send these patches soon to ml.

I noticed that if I add huge amount of credits for the connection, then
the issue is not seen. So when the credits are exhausted in receiving
end, the l2cap sends message to other end, see the backtrace below
(l2cap_recv_frame() followed by l2cap_do_send()).

At the same time a lot of data is pushed through the 6lowpan link. These
operations then conflict as seen in the log below.

One way to reproduce the issue is like this:

host1# nc -6 -l 9999 > /dev/null

host2# nc -6 fe80::21e:abff:fe4c:5257%bt0 9999 < /dev/urandom


Any ideas how to solve this?

Is there a bug in l2cap/hci layers or am I doing something wrong with
6lowpan connection?


 =================================
 [ INFO: inconsistent lock state ]
 3.17.0-rc1-bt6lowpan #1 Not tainted
 ---------------------------------
 inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage.
 kworker/u3:1/384 [HC0[0]:SC0[0]:HE1:SE1] takes:
  (&(&list->lock)->rlock#6){+.?...}, at: [<f831dd4c>] hci_send_acl
+0xac/0x290 [bluetooth]
 {IN-SOFTIRQ-W} state was registered at:
   [<c10915a3>] __lock_acquire+0x6d3/0x1d20
   [<c109325d>] lock_acquire+0x9d/0x140
   [<c1889c25>] _raw_spin_lock+0x45/0x80
   [<f831dd4c>] hci_send_acl+0xac/0x290 [bluetooth]
   [<f833efe0>] l2cap_do_send+0x60/0x100 [bluetooth]
   [<f8342bb0>] l2cap_chan_send+0x7f0/0x10e0 [bluetooth]
   [<f88dc8ee>] send_pkt+0x4e/0xa0 [bluetooth_6lowpan]
   [<f88dcd6e>] bt_xmit+0x42e/0x890 [bluetooth_6lowpan]
   [<c17742f4>] dev_hard_start_xmit+0x344/0x670
   [<c17749ad>] __dev_queue_xmit+0x38d/0x680
   [<c1774caf>] dev_queue_xmit+0xf/0x20
   [<c177b8b0>] neigh_connected_output+0x130/0x1a0
   [<c1812a63>] ip6_finish_output2+0x173/0x8c0
   [<c18182db>] ip6_finish_output+0x7b/0x1b0
   [<c18184a7>] ip6_output+0x97/0x2a0
   [<c183a46b>] mld_sendpack+0x5eb/0x650
   [<c183acc1>] mld_ifc_timer_expire+0x191/0x2f0
   [<c10ac385>] call_timer_fn+0x85/0x1c0
   [<c10acb72>] run_timer_softirq+0x192/0x280
   [<c104fd84>] __do_softirq+0xd4/0x300
   [<c10049fc>] do_softirq_own_stack+0x2c/0x40
   [<c1050136>] irq_exit+0x86/0xb0
   [<c188bd98>] smp_apic_timer_interrupt+0x38/0x50
   [<c188b6ce>] apic_timer_interrupt+0x32/0x38
 irq event stamp: 17003
 hardirqs last  enabled at (17003): [<c188a065>]
_raw_spin_unlock_irqrestore+0x55/0x70
 hardirqs last disabled at (17002): [<c1889e03>] _raw_spin_lock_irqsave
+0x23/0x90
 softirqs last  enabled at (6648): [<c104ff5c>] __do_softirq+0x2ac/0x300
 softirqs last disabled at (6619): [<c10049fc>] do_softirq_own_stack
+0x2c/0x40
 
 other info that might help us debug this:
  Possible unsafe locking scenario:
 
        CPU0
        ----
   lock(&(&list->lock)->rlock#6);
   <Interrupt>
     lock(&(&list->lock)->rlock#6);
 
  *** DEADLOCK ***
 
 3 locks held by kworker/u3:1/384:
  #0:  ("%s"hdev->name#2){.+.+.+}, at: [<c10622c3>] process_one_work
+0x113/0x4a0
  #1:  ((&hdev->rx_work)){+.+.+.}, at: [<c10622c3>] process_one_work
+0x113/0x4a0
  #2:  (&chan->lock){+.+.+.}, at: [<f833e569>] l2cap_get_chan_by_dcid
+0x89/0x90 [bluetooth]
 
 stack backtrace:
 CPU: 0 PID: 384 Comm: kworker/u3:1 Not tainted 3.17.0-rc1-bt6lowpan #1
 Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox
12/01/2006
 Workqueue: hci0 hci_rx_work [bluetooth]
  f4700000 00000000 f466bb90 c18821c1 c2344320 f466bbb0 c1880a94
c1ad9264
  c1ad9201 c1ad95f8 f4700614 00000006 c108e0c0 f466bbe0 c108ea8c
00000006
  f4700000 f466bffc 323ca8b2 0000002a 00000004 f4700000 f4700618
00000003
 Call Trace:
  [<c18821c1>] dump_stack+0x4b/0x75
  [<c1880a94>] print_usage_bug.part.36+0x209/0x213
  [<c108e0c0>] ? check_usage_forwards+0x110/0x110
  [<c108ea8c>] mark_lock+0x11c/0x6e0
  [<c10915e4>] __lock_acquire+0x714/0x1d20
  [<c1004b6f>] ? dump_trace+0xcf/0x1f0
  [<c100a5f8>] ? sched_clock+0x8/0x10
  [<c1075da9>] ? sched_clock_local+0x49/0x180
  [<c109325d>] lock_acquire+0x9d/0x140
  [<f831dd4c>] ? hci_send_acl+0xac/0x290 [bluetooth]
  [<c1889c25>] _raw_spin_lock+0x45/0x80
  [<f831dd4c>] ? hci_send_acl+0xac/0x290 [bluetooth]
  [<f831dd4c>] hci_send_acl+0xac/0x290 [bluetooth]
  [<c108f0b4>] ? mark_held_locks+0x64/0x90
  [<c188a065>] ? _raw_spin_unlock_irqrestore+0x55/0x70
  [<f833efe0>] l2cap_do_send+0x60/0x100 [bluetooth]
  [<c108f32b>] ? trace_hardirqs_on+0xb/0x10
  [<c188a051>] ? _raw_spin_unlock_irqrestore+0x41/0x70
  [<c1763125>] ? skb_dequeue+0x45/0x60
  [<f8349785>] l2cap_recv_frame+0x23e5/0x2dc0 [bluetooth]
  [<c1075da9>] ? sched_clock_local+0x49/0x180
  [<c100a5f8>] ? sched_clock+0x8/0x10
  [<c1075da9>] ? sched_clock_local+0x49/0x180
  [<c10761ef>] ? sched_clock_cpu+0x10f/0x160
  [<c107183b>] ? get_parent_ip+0xb/0x40
  [<c10718bb>] ? preempt_count_add+0x4b/0xa0
  [<c13d09e2>] ? debug_smp_processor_id+0x12/0x20
  [<c108cc04>] ? get_lock_stats+0x24/0x40
  [<c108f0b4>] ? mark_held_locks+0x64/0x90
  [<c188716d>] ? __mutex_unlock_slowpath+0xcd/0x1b0
  [<c13d09ff>] ? __this_cpu_preempt_check+0xf/0x20
  [<c108f1d4>] ? trace_hardirqs_on_caller+0xf4/0x240
  [<c108c9a6>] ? trace_hardirqs_off_caller+0xb6/0x160
  [<f834b6a9>] l2cap_recv_acldata+0x2f9/0x340 [bluetooth]
  [<f8316a13>] ? hci_rx_work+0x113/0x4a0 [bluetooth]
  [<f8316c69>] hci_rx_work+0x369/0x4a0 [bluetooth]
  [<f8316a13>] ? hci_rx_work+0x113/0x4a0 [bluetooth]
  [<c106234a>] process_one_work+0x19a/0x4a0
  [<c10622c3>] ? process_one_work+0x113/0x4a0
  [<c10629e9>] worker_thread+0x39/0x440
  [<c10629b0>] ? init_pwq+0xc0/0xc0
  [<c1066dc8>] kthread+0xa8/0xc0
  [<c108f32b>] ? trace_hardirqs_on+0xb/0x10
  [<c188ad01>] ret_from_kernel_thread+0x21/0x30
  [<c1066d20>] ? kthread_create_on_node+0x160/0x160



Cheers,
Jukka

^ permalink raw reply

* [PATCH] hciattach: Add sleep|nosleep keyword
From: Andrei Emeltchenko @ 2014-10-17 12:48 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 tools/hciattach.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tools/hciattach.c b/tools/hciattach.c
index d8ef7e7..808bbac 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -1276,7 +1276,9 @@ static void usage(void)
 {
 	printf("hciattach - HCI UART driver initialization utility\n");
 	printf("Usage:\n");
-	printf("\thciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]\n");
+	printf("\thciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed]"
+			" <tty> <type | id> [speed] [flow|noflow]"
+			" [sleep|nosleep] [bdaddr]\n");
 	printf("\thciattach -l\n");
 }
 
-- 
1.9.1


^ permalink raw reply related

* [PATCH 1/6] bnep: Avoid double error print for bnep_connadd()
From: Andrei Emeltchenko @ 2014-10-17 12:54 UTC (permalink / raw)
  To: linux-bluetooth

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

This avoids double printing the same error with bnep connection add
ioctl.
---
 profiles/network/bnep.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index 136709d..035beb1 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -316,10 +316,8 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
 	setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
 
 	sk = g_io_channel_unix_get_fd(session->io);
-	if (bnep_connadd(sk, session->src, session->iface)) {
-		error("bnep conn could not be added");
+	if (bnep_connadd(sk, session->src, session->iface) < 0)
 		goto failed;
-	}
 
 	if (bnep_if_up(session->iface)) {
 		error("could not up %s", session->iface);
@@ -556,14 +554,14 @@ static int bnep_del_from_bridge(const char *devname, const char *bridge)
 int bnep_server_add(int sk, uint16_t dst, char *bridge, char *iface,
 						const bdaddr_t *addr)
 {
+	int err;
+
 	if (!bridge || !iface || !addr)
 		return -EINVAL;
 
-	if (bnep_connadd(sk, dst, iface) < 0) {
-		error("Can't add connection to the bridge %s: %s(%d)",
-						bridge, strerror(errno), errno);
-		return -errno;
-	}
+	err = bnep_connadd(sk, dst, iface);
+	if (err < 0)
+		return err;
 
 	if (bnep_add_to_bridge(iface, bridge) < 0) {
 		error("Can't add %s to the bridge %s: %s(%d)",
-- 
1.9.1


^ permalink raw reply related

* [PATCH 2/6] bnep: Make error logging more descriptive
From: Andrei Emeltchenko @ 2014-10-17 12:54 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413550450-16577-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Add "bnep" before error message.
---
 profiles/network/bnep.c | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index 035beb1..e17a130 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -140,7 +140,7 @@ int bnep_init(void)
 		if (err == -EPROTONOSUPPORT)
 			warn("kernel lacks bnep-protocol support");
 		else
-			error("Failed to open control socket: %s (%d)",
+			error("bnep: Failed to open control socket: %s (%d)",
 						strerror(-err), -err);
 
 		return err;
@@ -164,7 +164,7 @@ static int bnep_conndel(const bdaddr_t *dst)
 	req.flags = 0;
 	if (ioctl(ctl, BNEPCONNDEL, &req)) {
 		int err = -errno;
-		error("Failed to kill connection: %s (%d)",
+		error("bnep: Failed to kill connection: %s (%d)",
 						strerror(-err), -err);
 		return err;
 	}
@@ -183,7 +183,7 @@ static int bnep_connadd(int sk, uint16_t role, char *dev)
 	req.role = role;
 	if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
 		int err = -errno;
-		error("Failed to add device %s: %s(%d)",
+		error("bnep: Failed to add device %s: %s(%d)",
 				dev, strerror(-err), -err);
 		return err;
 	}
@@ -210,7 +210,7 @@ static int bnep_if_up(const char *devname)
 	close(sk);
 
 	if (err < 0) {
-		error("Could not bring up %s", devname);
+		error("bnep: Could not bring up %s", devname);
 		return err;
 	}
 
@@ -235,7 +235,7 @@ static int bnep_if_down(const char *devname)
 	close(sk);
 
 	if (err < 0) {
-		error("Could not bring down %s", devname);
+		error("bnep: Could not bring down %s", devname);
 		return err;
 	}
 
@@ -272,7 +272,7 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
 	}
 
 	if (cond & (G_IO_HUP | G_IO_ERR)) {
-		error("Hangup or error on l2cap server socket");
+		error("bnep: Hangup or error on l2cap server socket");
 		goto failed;
 	}
 
@@ -280,25 +280,25 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
 	memset(pkt, 0, BNEP_MTU);
 	r = read(sk, pkt, sizeof(pkt) - 1);
 	if (r < 0) {
-		error("IO Channel read error");
+		error("bnep: IO Channel read error");
 		goto failed;
 	}
 
 	if (r == 0) {
-		error("No packet received on l2cap socket");
+		error("bnep: No packet received on l2cap socket");
 		goto failed;
 	}
 
 	errno = EPROTO;
 
 	if ((size_t) r < sizeof(*rsp)) {
-		error("Packet received is not bnep type");
+		error("bnep: Packet received is not bnep type");
 		goto failed;
 	}
 
 	rsp = (void *) pkt;
 	if (rsp->type != BNEP_CONTROL) {
-		error("Packet received is not bnep type");
+		error("bnep: Packet received is not bnep type");
 		goto failed;
 	}
 
@@ -307,7 +307,7 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
 
 	r = ntohs(rsp->resp);
 	if (r != BNEP_SUCCESS) {
-		error("bnep failed");
+		error("bnep: failed");
 		goto failed;
 	}
 
@@ -320,7 +320,7 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
 		goto failed;
 
 	if (bnep_if_up(session->iface)) {
-		error("could not up %s", session->iface);
+		error("bnep: could not up %s", session->iface);
 		bnep_conndel(&session->dst_addr);
 		goto failed;
 	}
@@ -359,7 +359,7 @@ static int bnep_setup_conn_req(struct bnep *session)
 
 	fd = g_io_channel_unix_get_fd(session->io);
 	if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) {
-		error("bnep connection req send failed: %s", strerror(errno));
+		error("bnep: connection req send failed: %s", strerror(errno));
 		return -errno;
 	}
 
@@ -373,9 +373,9 @@ static gboolean bnep_conn_req_to(gpointer user_data)
 	struct bnep *session = user_data;
 
 	if (session->attempts == CON_SETUP_RETRIES) {
-		error("Too many bnep connection attempts");
+		error("bnep: Too many bnep connection attempts");
 	} else {
-		error("bnep connection setup TO, retrying...");
+		error("bnep: connection setup TO, retrying...");
 		if (bnep_setup_conn_req(session) == 0)
 			return TRUE;
 	}
@@ -444,7 +444,7 @@ int bnep_connect(struct bnep *session, bnep_connect_cb conn_cb, void *data)
 	bt_io_get(session->io, &gerr, BT_IO_OPT_DEST_BDADDR, &session->dst_addr,
 							BT_IO_OPT_INVALID);
 	if (gerr) {
-		error("%s", gerr->message);
+		error("bnep: connect failed: %s", gerr->message);
 		g_error_free(gerr);
 		return -EINVAL;
 	}
@@ -564,14 +564,14 @@ int bnep_server_add(int sk, uint16_t dst, char *bridge, char *iface,
 		return err;
 
 	if (bnep_add_to_bridge(iface, bridge) < 0) {
-		error("Can't add %s to the bridge %s: %s(%d)",
+		error("bnep: Can't add %s to the bridge %s: %s(%d)",
 					iface, bridge, strerror(errno), errno);
 		bnep_conndel(addr);
 		return -errno;
 	}
 
 	if (bnep_if_up(iface) < 0) {
-		error("Can't up the interface %s: %s(%d)",
+		error("bnep: Can't up the interface %s: %s(%d)",
 						iface, strerror(errno), errno);
 		return -errno;
 	}
-- 
1.9.1


^ permalink raw reply related

* [PATCH 3/6] bnep: Refactor bnep_if_up() returning -errno
From: Andrei Emeltchenko @ 2014-10-17 12:54 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413550450-16577-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Some functions are using bnep_if_up() like bnep_server_add() referring
directly to errno which may be overwritten already.
---
 profiles/network/bnep.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index e17a130..3a6e3a4 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -195,7 +195,7 @@ static int bnep_connadd(int sk, uint16_t role, char *dev)
 static int bnep_if_up(const char *devname)
 {
 	struct ifreq ifr;
-	int sk, err;
+	int sk, err = 0;
 
 	sk = socket(AF_INET, SOCK_DGRAM, 0);
 
@@ -205,16 +205,15 @@ static int bnep_if_up(const char *devname)
 	ifr.ifr_flags |= IFF_UP;
 	ifr.ifr_flags |= IFF_MULTICAST;
 
-	err = ioctl(sk, SIOCSIFFLAGS, (void *) &ifr);
+	if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) < 0) {
+		err = -errno;
+		error("bnep: Could not bring up %s: %s(%d)",
+				devname, strerror(-err), -err);
+	}
 
 	close(sk);
 
-	if (err < 0) {
-		error("bnep: Could not bring up %s", devname);
-		return err;
-	}
-
-	return 0;
+	return err;
 }
 
 static int bnep_if_down(const char *devname)
-- 
1.9.1


^ permalink raw reply related

* [PATCH 4/6] bnep: Fix incorrect errno use and avoid double printing
From: Andrei Emeltchenko @ 2014-10-17 12:54 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413550450-16577-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Fixes bnep_if_up() usage since it already prints error message and
returns errno.
---
 profiles/network/bnep.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index 3a6e3a4..b8d2985 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -319,7 +319,6 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
 		goto failed;
 
 	if (bnep_if_up(session->iface)) {
-		error("bnep: could not up %s", session->iface);
 		bnep_conndel(&session->dst_addr);
 		goto failed;
 	}
@@ -569,13 +568,7 @@ int bnep_server_add(int sk, uint16_t dst, char *bridge, char *iface,
 		return -errno;
 	}
 
-	if (bnep_if_up(iface) < 0) {
-		error("bnep: Can't up the interface %s: %s(%d)",
-						iface, strerror(errno), errno);
-		return -errno;
-	}
-
-	return 0;
+	return bnep_if_up(iface);
 }
 
 void bnep_server_delete(char *bridge, char *iface, const bdaddr_t *addr)
-- 
1.9.1


^ permalink raw reply related

* [PATCH 5/6] bnep: Fix incorrect ioctl() check
From: Andrei Emeltchenko @ 2014-10-17 12:54 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413550450-16577-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

---
 profiles/network/bnep.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index b8d2985..18051c3 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -162,7 +162,7 @@ static int bnep_conndel(const bdaddr_t *dst)
 	memset(&req, 0, sizeof(req));
 	baswap((bdaddr_t *)&req.dst, dst);
 	req.flags = 0;
-	if (ioctl(ctl, BNEPCONNDEL, &req)) {
+	if (ioctl(ctl, BNEPCONNDEL, &req) < 0) {
 		int err = -errno;
 		error("bnep: Failed to kill connection: %s (%d)",
 						strerror(-err), -err);
-- 
1.9.1


^ permalink raw reply related

* [PATCH 6/6] bnep: Fix bnep_add_to_bridge() errno usage
From: Andrei Emeltchenko @ 2014-10-17 12:54 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413550450-16577-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Avoid errno be overwritten and make code consistent.
---
 profiles/network/bnep.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index 18051c3..c40ed69 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -491,7 +491,7 @@ static int bnep_add_to_bridge(const char *devname, const char *bridge)
 {
 	int ifindex;
 	struct ifreq ifr;
-	int sk, err;
+	int sk, err = 0;
 
 	if (!devname || !bridge)
 		return -EINVAL;
@@ -506,16 +506,16 @@ static int bnep_add_to_bridge(const char *devname, const char *bridge)
 	strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
 	ifr.ifr_ifindex = ifindex;
 
-	err = ioctl(sk, SIOCBRADDIF, &ifr);
+	if (ioctl(sk, SIOCBRADDIF, &ifr) < 0) {
+		err = -errno;
+		error("bnep: Can't add %s to the bridge %s: %s(%d)",
+					devname, bridge, strerror(-err), -err);
+	} else
+		info("bridge %s: interface %s added", bridge, devname);
 
 	close(sk);
 
-	if (err < 0)
-		return err;
-
-	info("bridge %s: interface %s added", bridge, devname);
-
-	return 0;
+	return err;
 }
 
 static int bnep_del_from_bridge(const char *devname, const char *bridge)
@@ -561,11 +561,10 @@ int bnep_server_add(int sk, uint16_t dst, char *bridge, char *iface,
 	if (err < 0)
 		return err;
 
-	if (bnep_add_to_bridge(iface, bridge) < 0) {
-		error("bnep: Can't add %s to the bridge %s: %s(%d)",
-					iface, bridge, strerror(errno), errno);
+	err = bnep_add_to_bridge(iface, bridge);
+	if (err < 0) {
 		bnep_conndel(addr);
-		return -errno;
+		return err;
 	}
 
 	return bnep_if_up(iface);
-- 
1.9.1


^ permalink raw reply related

* RE: [PATCH ] obexd/mas: Add Support fo MSETime filter
From: Bharat Bhusan Panda @ 2014-10-17 12:54 UTC (permalink / raw)
  To: 'Luiz Augusto von Dentz'; +Cc: linux-bluetooth, cpgs
In-Reply-To: <CABBYNZJ5Kq4z67EKhnH9pmL02jkW3begif2=s=qxYH+VeNBSzw@mail.gmail.com>

Hi Luiz,

> > ---
> >  obexd/plugins/mas.c | 28 ++++++++++++++++++++++++++++
> >  1 file changed, 28 insertions(+)
> >
> > diff --git a/obexd/plugins/mas.c b/obexd/plugins/mas.c index
> > fb97fe3..7f14bf8 100644
> > --- a/obexd/plugins/mas.c
> > +++ b/obexd/plugins/mas.c
> > @@ -30,6 +30,7 @@
> >  #include <glib.h>
> >  #include <fcntl.h>
> >  #include <inttypes.h>
> > +#include <sys/time.h>
> >
> >  #include <gobex/gobex.h>
> >  #include <gobex/gobex-apparam.h>
> > @@ -228,6 +229,25 @@ static void
> g_string_append_escaped_printf(GString *string,
> >         va_end(ap);
> >  }
> >
> > +static gchar *get_mse_timestamp(void) {
> > +       struct timeval time_val;
> > +       struct tm ltime;
> > +       gchar *local_ts;
> > +
> > +       gettimeofday(&time_val, NULL);
> > +
> > +       if (!localtime_r(&time_val.tv_sec, &ltime))
> > +               return NULL;
> > +
> > +       local_ts = g_strdup_printf("%04d%02d%02dT%02d%02d%02d",
> > +                                       ltime.tm_year + 1900, ltime.tm_mon + 1,
> > +                                       ltime.tm_mday, ltime.tm_hour,
> > +                                       ltime.tm_min, ltime.tm_sec);
> > +
> > +       return local_ts;
> > +}
> > +
> >  static const char *yesorno(gboolean a)  {
> >         if (a)
> > @@ -243,6 +263,7 @@ static void get_messages_listing_cb(void *session,
> > int err, uint16_t size,  {
> >         struct mas_session *mas = user_data;
> >         uint16_t max = 1024;
> > +       gchar *mse_time;
> >
> >         if (err < 0 && err != -EAGAIN) {
> >                 obex_object_set_io_flags(mas, G_IO_ERR, err); @@
> > -358,6 +379,13 @@ proceed:
> >                 mas->outparams = g_obex_apparam_set_uint8(mas->outparams,
> >                                                 MAP_AP_NEWMESSAGE,
> >                                                 newmsg ? 1 : 0);
> > +               /* Response to report the local time of MSE */
> > +               mse_time = get_mse_timestamp();
> > +               if (mse_time) {
> > +                       g_obex_apparam_set_string(mas->outparams,
> > +                                               MAP_AP_MSETIME, mse_time);
> > +                       g_free(mse_time);
> > +               }
> >         }
> >
> >         if (err != -EAGAIN)
> > --
> > 1.9.1
> 
> Does this works when the system has timedated running, perhaps we need
> to know if the time is set in UTC or not and in case of the later we probably
> need to provide the timezone as well.
>
Yes it works with system-timedated running. Only thing need to handle here is for different timezone other than UTC/GMT.
In further patches I will try to provide support with handling other timezones as well.
 
Best Regards,
Bharat



^ permalink raw reply

* Re: Locking issue when running out of credits in 6lowpan connection
From: Peter Hurley @ 2014-10-17 13:01 UTC (permalink / raw)
  To: Jukka Rissanen, linux-bluetooth; +Cc: Johan Hedberg, Marcel Holtmann
In-Reply-To: <1413549465.2705.149.camel@jrissane-mobl.ger.corp.intel.com>

On 10/17/2014 08:37 AM, Jukka Rissanen wrote:
> Hi,
> 
> I have seen the deadlock warnings from lockdep when pushing lot of data
> through a 6lowpan link. I was converting the read/write locks in 6lowpan
> to use RCU and it helped the situation slightly as I see the lockdep
> warning less now. I will send these patches soon to ml.
> 
> I noticed that if I add huge amount of credits for the connection, then
> the issue is not seen. So when the credits are exhausted in receiving
> end, the l2cap sends message to other end, see the backtrace below
> (l2cap_recv_frame() followed by l2cap_do_send()).
> 
> At the same time a lot of data is pushed through the 6lowpan link. These
> operations then conflict as seen in the log below.
> 
> One way to reproduce the issue is like this:
> 
> host1# nc -6 -l 9999 > /dev/null
> 
> host2# nc -6 fe80::21e:abff:fe4c:5257%bt0 9999 < /dev/urandom
> 
> 
> Any ideas how to solve this?

The spin_lock() in hci_queue_acl() still needs to be spin_lock_bh().

Regards,
Peter Hurley

> Is there a bug in l2cap/hci layers or am I doing something wrong with
> 6lowpan connection?
> 
> 
>  =================================
>  [ INFO: inconsistent lock state ]
>  3.17.0-rc1-bt6lowpan #1 Not tainted
>  ---------------------------------
>  inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage.
>  kworker/u3:1/384 [HC0[0]:SC0[0]:HE1:SE1] takes:
>   (&(&list->lock)->rlock#6){+.?...}, at: [<f831dd4c>] hci_send_acl
> +0xac/0x290 [bluetooth]
>  {IN-SOFTIRQ-W} state was registered at:
>    [<c10915a3>] __lock_acquire+0x6d3/0x1d20
>    [<c109325d>] lock_acquire+0x9d/0x140
>    [<c1889c25>] _raw_spin_lock+0x45/0x80
>    [<f831dd4c>] hci_send_acl+0xac/0x290 [bluetooth]
>    [<f833efe0>] l2cap_do_send+0x60/0x100 [bluetooth]
>    [<f8342bb0>] l2cap_chan_send+0x7f0/0x10e0 [bluetooth]
>    [<f88dc8ee>] send_pkt+0x4e/0xa0 [bluetooth_6lowpan]
>    [<f88dcd6e>] bt_xmit+0x42e/0x890 [bluetooth_6lowpan]
>    [<c17742f4>] dev_hard_start_xmit+0x344/0x670
>    [<c17749ad>] __dev_queue_xmit+0x38d/0x680
>    [<c1774caf>] dev_queue_xmit+0xf/0x20
>    [<c177b8b0>] neigh_connected_output+0x130/0x1a0
>    [<c1812a63>] ip6_finish_output2+0x173/0x8c0
>    [<c18182db>] ip6_finish_output+0x7b/0x1b0
>    [<c18184a7>] ip6_output+0x97/0x2a0
>    [<c183a46b>] mld_sendpack+0x5eb/0x650
>    [<c183acc1>] mld_ifc_timer_expire+0x191/0x2f0
>    [<c10ac385>] call_timer_fn+0x85/0x1c0
>    [<c10acb72>] run_timer_softirq+0x192/0x280
>    [<c104fd84>] __do_softirq+0xd4/0x300
>    [<c10049fc>] do_softirq_own_stack+0x2c/0x40
>    [<c1050136>] irq_exit+0x86/0xb0
>    [<c188bd98>] smp_apic_timer_interrupt+0x38/0x50
>    [<c188b6ce>] apic_timer_interrupt+0x32/0x38
>  irq event stamp: 17003
>  hardirqs last  enabled at (17003): [<c188a065>]
> _raw_spin_unlock_irqrestore+0x55/0x70
>  hardirqs last disabled at (17002): [<c1889e03>] _raw_spin_lock_irqsave
> +0x23/0x90
>  softirqs last  enabled at (6648): [<c104ff5c>] __do_softirq+0x2ac/0x300
>  softirqs last disabled at (6619): [<c10049fc>] do_softirq_own_stack
> +0x2c/0x40
>  
>  other info that might help us debug this:
>   Possible unsafe locking scenario:
>  
>         CPU0
>         ----
>    lock(&(&list->lock)->rlock#6);
>    <Interrupt>
>      lock(&(&list->lock)->rlock#6);
>  
>   *** DEADLOCK ***
>  
>  3 locks held by kworker/u3:1/384:
>   #0:  ("%s"hdev->name#2){.+.+.+}, at: [<c10622c3>] process_one_work
> +0x113/0x4a0
>   #1:  ((&hdev->rx_work)){+.+.+.}, at: [<c10622c3>] process_one_work
> +0x113/0x4a0
>   #2:  (&chan->lock){+.+.+.}, at: [<f833e569>] l2cap_get_chan_by_dcid
> +0x89/0x90 [bluetooth]
>  
>  stack backtrace:
>  CPU: 0 PID: 384 Comm: kworker/u3:1 Not tainted 3.17.0-rc1-bt6lowpan #1
>  Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox
> 12/01/2006
>  Workqueue: hci0 hci_rx_work [bluetooth]
>   f4700000 00000000 f466bb90 c18821c1 c2344320 f466bbb0 c1880a94
> c1ad9264
>   c1ad9201 c1ad95f8 f4700614 00000006 c108e0c0 f466bbe0 c108ea8c
> 00000006
>   f4700000 f466bffc 323ca8b2 0000002a 00000004 f4700000 f4700618
> 00000003
>  Call Trace:
>   [<c18821c1>] dump_stack+0x4b/0x75
>   [<c1880a94>] print_usage_bug.part.36+0x209/0x213
>   [<c108e0c0>] ? check_usage_forwards+0x110/0x110
>   [<c108ea8c>] mark_lock+0x11c/0x6e0
>   [<c10915e4>] __lock_acquire+0x714/0x1d20
>   [<c1004b6f>] ? dump_trace+0xcf/0x1f0
>   [<c100a5f8>] ? sched_clock+0x8/0x10
>   [<c1075da9>] ? sched_clock_local+0x49/0x180
>   [<c109325d>] lock_acquire+0x9d/0x140
>   [<f831dd4c>] ? hci_send_acl+0xac/0x290 [bluetooth]
>   [<c1889c25>] _raw_spin_lock+0x45/0x80
>   [<f831dd4c>] ? hci_send_acl+0xac/0x290 [bluetooth]
>   [<f831dd4c>] hci_send_acl+0xac/0x290 [bluetooth]
>   [<c108f0b4>] ? mark_held_locks+0x64/0x90
>   [<c188a065>] ? _raw_spin_unlock_irqrestore+0x55/0x70
>   [<f833efe0>] l2cap_do_send+0x60/0x100 [bluetooth]
>   [<c108f32b>] ? trace_hardirqs_on+0xb/0x10
>   [<c188a051>] ? _raw_spin_unlock_irqrestore+0x41/0x70
>   [<c1763125>] ? skb_dequeue+0x45/0x60
>   [<f8349785>] l2cap_recv_frame+0x23e5/0x2dc0 [bluetooth]
>   [<c1075da9>] ? sched_clock_local+0x49/0x180
>   [<c100a5f8>] ? sched_clock+0x8/0x10
>   [<c1075da9>] ? sched_clock_local+0x49/0x180
>   [<c10761ef>] ? sched_clock_cpu+0x10f/0x160
>   [<c107183b>] ? get_parent_ip+0xb/0x40
>   [<c10718bb>] ? preempt_count_add+0x4b/0xa0
>   [<c13d09e2>] ? debug_smp_processor_id+0x12/0x20
>   [<c108cc04>] ? get_lock_stats+0x24/0x40
>   [<c108f0b4>] ? mark_held_locks+0x64/0x90
>   [<c188716d>] ? __mutex_unlock_slowpath+0xcd/0x1b0
>   [<c13d09ff>] ? __this_cpu_preempt_check+0xf/0x20
>   [<c108f1d4>] ? trace_hardirqs_on_caller+0xf4/0x240
>   [<c108c9a6>] ? trace_hardirqs_off_caller+0xb6/0x160
>   [<f834b6a9>] l2cap_recv_acldata+0x2f9/0x340 [bluetooth]
>   [<f8316a13>] ? hci_rx_work+0x113/0x4a0 [bluetooth]
>   [<f8316c69>] hci_rx_work+0x369/0x4a0 [bluetooth]
>   [<f8316a13>] ? hci_rx_work+0x113/0x4a0 [bluetooth]
>   [<c106234a>] process_one_work+0x19a/0x4a0
>   [<c10622c3>] ? process_one_work+0x113/0x4a0
>   [<c10629e9>] worker_thread+0x39/0x440
>   [<c10629b0>] ? init_pwq+0xc0/0xc0
>   [<c1066dc8>] kthread+0xa8/0xc0
>   [<c108f32b>] ? trace_hardirqs_on+0xb/0x10
>   [<c188ad01>] ret_from_kernel_thread+0x21/0x30
>   [<c1066d20>] ? kthread_create_on_node+0x160/0x160

^ permalink raw reply

* [PATCH] android/pts: Update PTS files for DIS
From: Sebastian Chlad @ 2014-10-17 13:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sebastian Chlad

PICS and PIXITs updated to PTS 5.3. Regression done for Android
4.4.4.
---
 android/pics-dis.txt  | 2 +-
 android/pixit-dis.txt | 4 ++--
 android/pts-dis.txt   | 7 +++++--
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/android/pics-dis.txt b/android/pics-dis.txt
index 0a1ab3f..169173d 100644
--- a/android/pics-dis.txt
+++ b/android/pics-dis.txt
@@ -1,6 +1,6 @@
 DIS PICS for the PTS tool.
 
-PTS version: 5.2
+PTS version: 5.3
 
 * - different than PTS defaults
 
diff --git a/android/pixit-dis.txt b/android/pixit-dis.txt
index c29ec36..71729fe 100644
--- a/android/pixit-dis.txt
+++ b/android/pixit-dis.txt
@@ -1,6 +1,6 @@
 DIS PIXIT for the PTS tool.
 
-PTS version: 5.2
+PTS version: 5.3
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
@@ -19,7 +19,7 @@ TSPX_delete_link_key					FALSE
 TSPX_pin_code						0000
 TSPX_use_dynamic_pin					FALSE
 TSPX_delete_ltk						FALSE
-TSPX_security_enabled					TRUE
+TSPX_security_enabled					TRUE (*)
 TSPX_iut_setup_att_over_br_edr				FALSE
 TSPX_tester_appearance					0000
 -------------------------------------------------------------------------------
diff --git a/android/pts-dis.txt b/android/pts-dis.txt
index 8489430..215baa2 100644
--- a/android/pts-dis.txt
+++ b/android/pts-dis.txt
@@ -1,7 +1,7 @@
 PTS test results for DIS
 
-PTS version: 5.2
-Tested: 29-July-2014
+PTS version: 5.3
+Tested: 18-October-2014
 Android version: 4.4.4
 
 Results:
@@ -11,6 +11,9 @@ INC	test is inconclusive
 N/A	test is disabled due to PICS setup
 NONE	test result is none
 
+NOTE: DIS testing might require some extra properties to be set. Please refer
+to the README file in android folder. Section: Customization.
+
 -------------------------------------------------------------------------------
 Test Name		Result	Notes
 -------------------------------------------------------------------------------
-- 
1.8.5.3


^ permalink raw reply related

* Re: [PATCH] Bluetooth: 6lowpan: remove unnecessary codes in give_skb_to_upper
From: Jukka Rissanen @ 2014-10-17 13:10 UTC (permalink / raw)
  To: roy.qing.li; +Cc: linux-bluetooth, marcel, gustavo, johan.hedberg
In-Reply-To: <1413426115-17077-1-git-send-email-roy.qing.li@gmail.com>

Hi,

On to, 2014-10-16 at 10:21 +0800, roy.qing.li@gmail.com wrote:
> From: Li RongQing <roy.qing.li@gmail.com>
> 
> netif_rx() only returns NET_RX_DROP and NET_RX_SUCCESS, not returns
> negative value
> 
> Signed-off-by: Li RongQing <roy.qing.li@gmail.com>
> ---
>  net/bluetooth/6lowpan.c |    9 +--------
>  1 file changed, 1 insertion(+), 8 deletions(-)
> 
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index c2e0d14..9b5c89b 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -249,19 +249,12 @@ static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn)
>  static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev)
>  {
>  	struct sk_buff *skb_cp;
> -	int ret;
>  
>  	skb_cp = skb_copy(skb, GFP_ATOMIC);
>  	if (!skb_cp)
>  		return -ENOMEM;
>  
> -	ret = netif_rx(skb_cp);
> -	if (ret < 0) {
> -		BT_DBG("receive skb %d", ret);
> -		return NET_RX_DROP;
> -	}
> -
> -	return ret;
> +	return netif_rx(skb_cp);
>  }
>  
>  static int process_data(struct sk_buff *skb, struct net_device *netdev,

Ack to this.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>


Cheers,
Jukka

^ permalink raw reply

* [PATCH 1/8] android/gatt: Fix return status if cannot alloc memory
From: Grzegorz Kolodziejczyk @ 2014-10-17 13:38 UTC (permalink / raw)
  To: linux-bluetooth

NOMEM HAL status should be returned in case if it's not possible to
alloc memory for notifiaction data.
---
 android/gatt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/gatt.c b/android/gatt.c
index ea20941..c26d45a 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -3759,7 +3759,7 @@ static void handle_client_register_for_notification(const void *buf,
 
 	notification = new0(struct notification_data, 1);
 	if (!notification) {
-		status = HAL_STATUS_FAILED;
+		status = HAL_STATUS_NOMEM;
 		goto failed;
 	}
 
-- 
1.9.3


^ permalink raw reply related

* [PATCH 2/8] android/tester: Define write types for GATT test cases
From: Grzegorz Kolodziejczyk @ 2014-10-17 13:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413553099-19689-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

Gatt test cases should use defined write types.
---
 android/tester-gatt.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 8b95e9c..38dd0ee 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -41,6 +41,11 @@
 #define GATT_SERVER_TRANSPORT_BREDR		0x01
 #define GATT_SERVER_TRANSPORT_LE_BREDR		0x02
 
+#define GATT_WRITE_TYPE_NO_RESPONSE	0x01
+#define GATT_WRITE_TYPE_DEFAULT		0x02
+#define GATT_WRITE_TYPE_PREPARE		0x03
+#define GATT_WRITE_TYPE_SIGNED		0x04
+
 static struct queue *list; /* List of gatt test cases */
 
 static int srvc1_handle;
@@ -368,7 +373,7 @@ static struct write_char_data write_char_data_1 = {
 	.conn_id = CONN1_ID,
 	.service = &service_1,
 	.characteristic = &characteristic_1,
-	.write_type = 1,
+	.write_type = GATT_WRITE_TYPE_NO_RESPONSE,
 	.len = sizeof(value_2),
 	.p_value = value_2,
 	.auth_req = 0
@@ -378,7 +383,7 @@ static struct write_char_data write_char_data_2 = {
 	.conn_id = CONN1_ID,
 	.service = &service_1,
 	.characteristic = &characteristic_1,
-	.write_type = 2,
+	.write_type = GATT_WRITE_TYPE_DEFAULT,
 	.len = sizeof(value_2),
 	.p_value = value_2,
 	.auth_req = 0
-- 
1.9.3


^ permalink raw reply related

* [PATCH 3/8] android/tester: Fix hardcoded length values
From: Grzegorz Kolodziejczyk @ 2014-10-17 13:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413553099-19689-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

Lenght variable shouldn't be hardcoded in test case structs.
---
 android/tester-gatt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 38dd0ee..97fe0f0 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -596,7 +596,7 @@ static struct set_read_params set_read_param_1 = {
 	.srvc_id = &service_1,
 	.char_id = &characteristic_1,
 	.value = value_1,
-	.len = 1,
+	.len = sizeof(value_1),
 	.status = BT_STATUS_SUCCESS
 };
 
@@ -620,7 +620,7 @@ static struct set_read_params set_read_param_4 = {
 	.char_id = &characteristic_1,
 	.descr_id = &desc_1,
 	.value = value_1,
-	.len = 1,
+	.len = sizeof(value_1),
 	.status = BT_STATUS_SUCCESS
 };
 
-- 
1.9.3


^ permalink raw reply related

* [PATCH 4/8] android/tester: Use BT_STATUS defines instead of hardcoded values
From: Grzegorz Kolodziejczyk @ 2014-10-17 13:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413553099-19689-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

Status value in test case structs should use defined BT_STATUS types.
---
 android/tester-gatt.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 97fe0f0..d123619 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -611,7 +611,7 @@ static struct set_read_params set_read_param_3 = {
 	.params = &read_params_1,
 	.srvc_id = &service_2,
 	.char_id = &characteristic_1,
-	.status = 0x01,
+	.status = BT_STATUS_FAIL
 };
 
 static struct set_read_params set_read_param_4 = {
@@ -637,7 +637,7 @@ static struct set_read_params set_read_param_6 = {
 	.srvc_id = &service_1,
 	.char_id = &characteristic_1,
 	.descr_id = &desc_2,
-	.status = 0x01
+	.status = BT_STATUS_FAIL
 };
 
 static struct set_write_params set_write_param_1 = {
@@ -658,7 +658,7 @@ static struct set_write_params set_write_param_3 = {
 	.params = &write_params_1,
 	.srvc_id = &service_1,
 	.char_id = &characteristic_1,
-	.status = 0x01
+	.status = BT_STATUS_FAIL
 };
 
 static struct set_write_params set_write_param_4 = {
@@ -674,7 +674,7 @@ static struct set_write_params set_write_param_5 = {
 	.srvc_id = &service_1,
 	.char_id = &characteristic_1,
 	.descr_id = &desc_2,
-	.status = 0x01
+	.status = BT_STATUS_FAIL
 };
 
 static struct set_write_params set_write_param_6 = {
-- 
1.9.3


^ permalink raw reply related

* [PATCH 5/8] android/tester: Add att pdu remote receive debug log
From: Grzegorz Kolodziejczyk @ 2014-10-17 13:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413553099-19689-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

This adds additional logs with received opcode of att pdu by remote
---
 android/tester-gatt.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index d123619..c0065a7 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -1457,6 +1457,8 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
 	const uint8_t *pdu = data;
 	struct iovec *gatt_pdu = queue_peek_head(t_data->pdus);
 
+	tester_debug("Received att pdu with opcode 0x%02x", pdu[0]);
+
 	switch (pdu[0]) {
 	case L2CAP_ATT_EXCHANGE_MTU_REQ:
 		tester_print("Exchange MTU request received.");
-- 
1.9.3


^ permalink raw reply related

* [PATCH 6/8] android/tester: Add GATT server send indication test cases
From: Grzegorz Kolodziejczyk @ 2014-10-17 13:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413553099-19689-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

This adds send indication by server test cases.
---
 android/tester-gatt.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++-
 android/tester-main.c |   2 +
 android/tester-main.h |   2 +
 3 files changed, 162 insertions(+), 2 deletions(-)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index c0065a7..2ceb295 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -23,6 +23,8 @@
 
 #define L2CAP_ATT_EXCHANGE_MTU_REQ	0x02
 #define L2CAP_ATT_EXCHANGE_MTU_RSP	0x03
+#define L2CAP_ATT_HANDLE_VALUE_NOTIFY	0x1b
+#define L2CAP_ATT_HANDLE_VALUE_IND	0x1d
 
 #define GATT_STATUS_SUCCESS	0x00000000
 #define GATT_STATUS_FAILURE	0x00000101
@@ -61,6 +63,8 @@ static bt_uuid_t app2_uuid = {
 				0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
 };
 
+static uint8_t value_1[] = {0x01};
+
 struct gatt_connect_data {
 	const int app_id;
 	const int conn_id;
@@ -174,6 +178,15 @@ struct delete_srvc_data {
 	int *srvc_handle;
 };
 
+struct send_indication_data {
+	int app_id;
+	int *attr_handle;
+	int conn_id;
+	int len;
+	int confirm;
+	char *p_value;
+};
+
 static bt_bdaddr_t emu_remote_bdaddr_val = {
 	.address = { 0x00, 0xaa, 0x01, 0x01, 0x00, 0x00 },
 };
@@ -560,6 +573,36 @@ static struct delete_srvc_data delete_bad_srvc_data_1 = {
 	.app_id = APP1_ID,
 	.srvc_handle = &srvc_bad_handle
 };
+
+static int srvc_indication_handle_1 = 0x01;
+
+static struct send_indication_data send_indication_data_1 = {
+	.app_id = APP1_ID,
+	.attr_handle = &srvc_indication_handle_1,
+	.conn_id = CONN1_ID,
+	.len = sizeof(value_2),
+	.p_value = value_2,
+	.confirm = 1
+};
+
+static struct send_indication_data send_indication_data_2 = {
+	.app_id = APP1_ID,
+	.attr_handle = &srvc_indication_handle_1,
+	.conn_id = CONN1_ID,
+	.len = sizeof(value_2),
+	.p_value = value_2,
+	.confirm = 0
+};
+
+static struct send_indication_data send_bad_indication_data_1 = {
+	.app_id = APP1_ID,
+	.attr_handle = &srvc_indication_handle_1,
+	.conn_id = CONN2_ID,
+	.len = sizeof(value_2),
+	.p_value = value_2,
+	.confirm = 0
+};
+
 struct set_read_params {
 	btgatt_read_params_t *params;
 	btgatt_srvc_id_t *srvc_id;
@@ -589,8 +632,6 @@ struct set_notify_params {
 	bt_bdaddr_t *bdaddr;
 };
 
-static uint8_t value_1[] = {0x01};
-
 static struct set_read_params set_read_param_1 = {
 	.params = &read_params_1,
 	.srvc_id = &service_1,
@@ -1004,6 +1045,17 @@ static struct iovec notification_3[] = {
 	end_pdu
 };
 
+static struct iovec send_indication_1[] = {
+	raw_pdu(0x1d, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03),
+	raw_pdu(0x1e),
+	end_pdu
+};
+
+static struct iovec send_notification_1[] = {
+	raw_pdu(0x1b, 0x01, 0x00, 0x00, 0x01, 0x02, 0x03),
+	end_pdu
+};
+
 static void gatt_client_register_action(void)
 {
 	struct test_data *data = tester_get_data();
@@ -1449,6 +1501,25 @@ static void gatt_server_delete_srvc_action(void)
 	schedule_action_verification(step);
 }
 
+static void gatt_server_send_indication_action(void)
+{
+	struct test_data *data = tester_get_data();
+	struct step *current_data_step = queue_peek_head(data->steps);
+	struct send_indication_data *send_indication_data =
+						current_data_step->set_data;
+	struct step *step = g_new0(struct step, 1);
+
+	step->action_status = data->if_gatt->server->send_indication(
+					send_indication_data->app_id,
+					*send_indication_data->attr_handle,
+					send_indication_data->conn_id,
+					send_indication_data->len,
+					send_indication_data->confirm,
+					send_indication_data->p_value);
+
+	schedule_action_verification(step);
+}
+
 static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
 {
 	struct test_data *t_data = tester_get_data();
@@ -1456,6 +1527,7 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
 	struct emu_l2cap_cid_data *cid_data = user_data;
 	const uint8_t *pdu = data;
 	struct iovec *gatt_pdu = queue_peek_head(t_data->pdus);
+	struct step *step;
 
 	tester_debug("Received att pdu with opcode 0x%02x", pdu[0]);
 
@@ -1473,6 +1545,20 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
 		tester_print("Exchange MTU response received.");
 
 		break;
+	case L2CAP_ATT_HANDLE_VALUE_IND:
+		step = g_new0(struct step, 1);
+
+		step->callback = CB_EMU_VALUE_INDICATION;
+
+		schedule_callback_verification(step);
+		break;
+	case L2CAP_ATT_HANDLE_VALUE_NOTIFY:
+		step = g_new0(struct step, 1);
+
+		step->callback = CB_EMU_VALUE_NOTIFICATION;
+
+		schedule_callback_verification(step);
+		break;
 	default:
 		if (!gatt_pdu || !gatt_pdu->iov_base) {
 			tester_print("Unknown ATT packet.");
@@ -3091,6 +3177,76 @@ static struct test_case test_cases[] = {
 		CALLBACK_GATTS_SERVICE_DELETED(GATT_STATUS_FAILURE, APP1_ID,
 									NULL),
 	),
+	TEST_CASE_BREDRLE("Gatt Server - Send Indication",
+		ACTION_SUCCESS(init_pdus, send_indication_1),
+		ACTION_SUCCESS(bluetooth_enable_action, NULL),
+		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+		ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+		ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+		ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+		ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
+		CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+		ACTION_SUCCESS(bt_start_discovery_action, NULL),
+		CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+							BT_DISCOVERY_STARTED),
+		CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+		ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+		ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+		CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+						prop_emu_remotes_default_set,
+						CONN1_ID, APP1_ID),
+		ACTION_SUCCESS(gatt_server_send_indication_action,
+						&send_indication_data_1),
+		CALLBACK(CB_EMU_VALUE_INDICATION),
+		ACTION_SUCCESS(bluetooth_disable_action, NULL),
+		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+	),
+	TEST_CASE_BREDRLE("Gatt Server - Send Notification",
+		ACTION_SUCCESS(init_pdus, send_notification_1),
+		ACTION_SUCCESS(bluetooth_enable_action, NULL),
+		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+		ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+		ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+		ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+		ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
+		CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+		ACTION_SUCCESS(bt_start_discovery_action, NULL),
+		CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+							BT_DISCOVERY_STARTED),
+		CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+		ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+		ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+		CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+						prop_emu_remotes_default_set,
+						CONN1_ID, APP1_ID),
+		ACTION_SUCCESS(gatt_server_send_indication_action,
+						&send_indication_data_2),
+		CALLBACK(CB_EMU_VALUE_NOTIFICATION),
+		ACTION_SUCCESS(bluetooth_disable_action, NULL),
+		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+	),
+	TEST_CASE_BREDRLE("Gatt Server - Send Notification, wrong conn id",
+		ACTION_SUCCESS(bluetooth_enable_action, NULL),
+		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+		ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+		ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+		ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+		ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
+		CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+		ACTION_SUCCESS(bt_start_discovery_action, NULL),
+		CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+							BT_DISCOVERY_STARTED),
+		CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+		ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+		ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+		CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+						prop_emu_remotes_default_set,
+						CONN1_ID, APP1_ID),
+		ACTION_FAIL(gatt_server_send_indication_action,
+						&send_bad_indication_data_1),
+		ACTION_SUCCESS(bluetooth_disable_action, NULL),
+		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+	),
 };
 
 struct queue *get_gatt_tests(void)
diff --git a/android/tester-main.c b/android/tester-main.c
index a804f11..1018cae 100644
--- a/android/tester-main.c
+++ b/android/tester-main.c
@@ -107,6 +107,8 @@ static struct {
 	DBG_CB(CB_EMU_ENCRYPTION_ENABLED),
 	DBG_CB(CB_EMU_ENCRYPTION_DISABLED),
 	DBG_CB(CB_EMU_CONNECTION_REJECTED),
+	DBG_CB(CB_EMU_VALUE_INDICATION),
+	DBG_CB(CB_EMU_VALUE_NOTIFICATION),
 };
 
 static gboolean check_callbacks_called(gpointer user_data)
diff --git a/android/tester-main.h b/android/tester-main.h
index 22c5c8b..31d271a 100644
--- a/android/tester-main.h
+++ b/android/tester-main.h
@@ -469,6 +469,8 @@ typedef enum {
 	CB_EMU_ENCRYPTION_ENABLED,
 	CB_EMU_ENCRYPTION_DISABLED,
 	CB_EMU_CONNECTION_REJECTED,
+	CB_EMU_VALUE_INDICATION,
+	CB_EMU_VALUE_NOTIFICATION,
 } expected_bt_callback_t;
 
 struct test_data {
-- 
1.9.3


^ permalink raw reply related

* [PATCH 7/8] android/tester: Add GATT server send response to read req test cases
From: Grzegorz Kolodziejczyk @ 2014-10-17 13:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413553099-19689-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

This adds send response by server to read request test cases.
---
 android/tester-gatt.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++
 android/tester-main.c |  65 ++++++++++++++++++++-
 android/tester-main.h |  27 +++++++++
 3 files changed, 244 insertions(+), 1 deletion(-)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 2ceb295..6655f2d 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -21,8 +21,12 @@
 #include "tester-main.h"
 #include "src/shared/util.h"
 
+#define ATT_HANDLE_SIZE	2
+
 #define L2CAP_ATT_EXCHANGE_MTU_REQ	0x02
 #define L2CAP_ATT_EXCHANGE_MTU_RSP	0x03
+#define L2CAP_ATT_READ_REQ		0x0a
+#define L2CAP_ATT_READ_RSP		0x0b
 #define L2CAP_ATT_HANDLE_VALUE_NOTIFY	0x1b
 #define L2CAP_ATT_HANDLE_VALUE_IND	0x1d
 
@@ -39,6 +43,8 @@
 #define CONN1_ID	1
 #define CONN2_ID	2
 
+#define TRANS1_ID	1
+
 #define GATT_SERVER_TRANSPORT_LE		0x00
 #define GATT_SERVER_TRANSPORT_BREDR		0x01
 #define GATT_SERVER_TRANSPORT_LE_BREDR		0x02
@@ -52,6 +58,13 @@ static struct queue *list; /* List of gatt test cases */
 
 static int srvc1_handle;
 static int inc_srvc1_handle;
+static int char1_handle;
+
+struct set_att_data {
+	char *to;
+	char *from;
+	int len;
+};
 
 static bt_uuid_t app1_uuid = {
 	.uu = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
@@ -187,6 +200,13 @@ struct send_indication_data {
 	char *p_value;
 };
 
+struct send_resp_data {
+	int conn_id;
+	int trans_id;
+	int status;
+	btgatt_response_t *response;
+};
+
 static bt_bdaddr_t emu_remote_bdaddr_val = {
 	.address = { 0x00, 0xaa, 0x01, 0x01, 0x00, 0x00 },
 };
@@ -746,6 +766,21 @@ static struct set_notify_params set_notify_param_2 = {
 	.bdaddr = &emu_remote_bdaddr_val
 };
 
+static btgatt_response_t response_1 = {
+	.handle = 0x1c,
+	.attr_value.auth_req = 0,
+	.attr_value.handle = 0x1d,
+	.attr_value.len = 0,
+	.attr_value.offset = 0,
+};
+
+static struct send_resp_data send_resp_data_1 = {
+	.conn_id = CONN1_ID,
+	.trans_id = TRANS1_ID,
+	.status = BT_STATUS_SUCCESS,
+	.response = &response_1,
+};
+
 static struct iovec search_service[] = {
 	raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
 	raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
@@ -1056,6 +1091,36 @@ static struct iovec send_notification_1[] = {
 	end_pdu
 };
 
+/* att commands define raw pdus */
+static struct iovec att_read_req = raw_pdu(0x0a, 0x00, 0x00);
+
+static void gatt_att_pdu_modify(void)
+{
+	struct test_data *data = tester_get_data();
+	struct step *current_data_step = queue_peek_head(data->steps);
+	struct iovec *store_pdu = current_data_step->set_data_to;
+	struct step *step = g_new0(struct step, 1);
+	unsigned char *raw_pdu = store_pdu->iov_base;
+	int set_data_len = current_data_step->set_data_len;
+
+	switch (raw_pdu[0]) {
+	case L2CAP_ATT_READ_REQ: {
+		uint16_t handle = *((int *)current_data_step->set_data);
+
+		memcpy(raw_pdu + 1, &handle, set_data_len);
+		tester_debug("gatt: modify pdu read request handle to 0x%02x",
+									handle);
+
+		break;
+	}
+
+	default:
+		break;
+	}
+
+	schedule_action_verification(step);
+}
+
 static void gatt_client_register_action(void)
 {
 	struct test_data *data = tester_get_data();
@@ -1520,6 +1585,22 @@ static void gatt_server_send_indication_action(void)
 	schedule_action_verification(step);
 }
 
+static void gatt_server_send_response_action(void)
+{
+	struct test_data *data = tester_get_data();
+	struct step *current_data_step = queue_peek_head(data->steps);
+	struct send_resp_data *send_resp_data = current_data_step->set_data;
+	struct step *step = g_new0(struct step, 1);
+
+	step->action_status = data->if_gatt->server->send_response(
+						send_resp_data->conn_id,
+						send_resp_data->trans_id,
+						send_resp_data->status,
+						send_resp_data->response);
+
+	schedule_action_verification(step);
+}
+
 static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
 {
 	struct test_data *t_data = tester_get_data();
@@ -1559,6 +1640,14 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
 
 		schedule_callback_verification(step);
 		break;
+	case L2CAP_ATT_READ_RSP:
+		/* TODO - More complicated cases should also verify pdu data */
+		step = g_new0(struct step, 1);
+
+		step->callback = CB_EMU_READ_RESPONSE;
+
+		schedule_callback_verification(step);
+		break;
 	default:
 		if (!gatt_pdu || !gatt_pdu->iov_base) {
 			tester_print("Unknown ATT packet.");
@@ -1607,6 +1696,26 @@ static void gatt_remote_send_frame_action(void)
 	schedule_action_verification(step);
 }
 
+static void gatt_remote_send_raw_pdu_action(void)
+{
+	struct test_data *data = tester_get_data();
+	struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+	struct step *current_data_step = queue_peek_head(data->steps);
+	struct iovec *pdu = current_data_step->set_data;
+	struct step *step = g_new0(struct step, 1);
+
+	if (cid_data.handle && cid_data.cid) {
+		bthost_send_cid_v(bthost, cid_data.handle, cid_data.cid,
+									pdu, 1);
+		step->action_status = BT_STATUS_SUCCESS;
+	} else {
+		tester_debug("No connection set up");
+		step->action_status = BT_STATUS_FAIL;
+	}
+
+	schedule_action_verification(step);
+}
+
 static void gatt_conn_cb(uint16_t handle, void *user_data)
 {
 	struct test_data *data = tester_get_data();
@@ -3247,6 +3356,50 @@ static struct test_case test_cases[] = {
 		ACTION_SUCCESS(bluetooth_disable_action, NULL),
 		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
 	),
+	TEST_CASE_BREDRLE("Gatt Server - Send response to read char request",
+		ACTION_SUCCESS(bluetooth_enable_action, NULL),
+		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+		ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+		ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+		ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+		ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
+		CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+		ACTION_SUCCESS(gatt_server_add_service_action,
+							&add_service_data_5),
+		CALLBACK_GATTS_SERVICE_ADDED(GATT_STATUS_SUCCESS, APP1_ID,
+							&service_add_1, NULL,
+							&srvc1_handle),
+		ACTION_SUCCESS(gatt_server_add_char_action, &add_char_data_1),
+		CALLBACK_GATTS_CHARACTERISTIC_ADDED(GATT_STATUS_SUCCESS,
+							APP1_ID, &app1_uuid,
+							&srvc1_handle, NULL,
+							&char1_handle),
+		ACTION_SUCCESS(gatt_server_start_srvc_action,
+							&start_srvc_data_2),
+		CALLBACK_GATTS_SERVICE_STARTED(GATT_STATUS_SUCCESS, APP1_ID,
+								&srvc1_handle),
+		ACTION_SUCCESS(bt_start_discovery_action, NULL),
+		CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+							BT_DISCOVERY_STARTED),
+		CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+		ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+		ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+		CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+						prop_emu_remotes_default_set,
+						CONN1_ID, APP1_ID),
+		MODIFY_DATA(GATT_STATUS_SUCCESS, gatt_att_pdu_modify,
+						&char1_handle, &att_read_req,
+						ATT_HANDLE_SIZE),
+		ACTION_SUCCESS(gatt_remote_send_raw_pdu_action, &att_read_req),
+		CALLBACK_GATTS_REQUEST_READ(CONN1_ID, TRANS1_ID,
+						prop_emu_remotes_default_set,
+						&char1_handle, 0, false),
+		ACTION_SUCCESS(gatt_server_send_response_action,
+							&send_resp_data_1),
+		CALLBACK(CB_EMU_READ_RESPONSE),
+		ACTION_SUCCESS(bluetooth_disable_action, NULL),
+		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+	),
 };
 
 struct queue *get_gatt_tests(void)
diff --git a/android/tester-main.c b/android/tester-main.c
index 1018cae..e9ebfdd 100644
--- a/android/tester-main.c
+++ b/android/tester-main.c
@@ -109,6 +109,7 @@ static struct {
 	DBG_CB(CB_EMU_CONNECTION_REJECTED),
 	DBG_CB(CB_EMU_VALUE_INDICATION),
 	DBG_CB(CB_EMU_VALUE_NOTIFICATION),
+	DBG_CB(CB_EMU_READ_RESPONSE),
 };
 
 static gboolean check_callbacks_called(gpointer user_data)
@@ -775,6 +776,16 @@ static bool match_data(struct step *step)
 		return false;
 	}
 
+	if (exp->callback_result.attr_handle &&
+					step->callback_result.attr_handle)
+		if (*exp->callback_result.attr_handle !=
+					*step->callback_result.attr_handle) {
+			tester_debug("Gatt attribute handle mismatch: %d vs %d",
+					*step->callback_result.attr_handle,
+					*exp->callback_result.attr_handle);
+			return false;
+		}
+
 	if (exp->callback_result.srvc_handle &&
 					step->callback_result.srvc_handle)
 		if (*exp->callback_result.srvc_handle !=
@@ -803,6 +814,27 @@ static bool match_data(struct step *step)
 			return false;
 		}
 
+	if (exp->callback_result.trans_id != step->callback_result.trans_id) {
+		tester_debug("Gatt trans id mismatch: %d vs %d",
+						exp->callback_result.trans_id,
+						step->callback_result.trans_id);
+		return false;
+	}
+
+	if (exp->callback_result.offset != step->callback_result.offset) {
+		tester_debug("Gatt offset mismatch: %d vs %d",
+						exp->callback_result.offset,
+						step->callback_result.offset);
+		return false;
+	}
+
+	if (exp->callback_result.is_long != step->callback_result.is_long) {
+		tester_debug("Gatt is long attr value flag mismatch: %d vs %d",
+						exp->callback_result.is_long,
+						step->callback_result.is_long);
+		return false;
+	}
+
 	if (exp->store_srvc_handle)
 		memcpy(exp->store_srvc_handle,
 					step->callback_result.srvc_handle,
@@ -931,6 +963,9 @@ static void destroy_callback_step(void *data)
 	if (step->callback_result.desc_handle)
 		free(step->callback_result.desc_handle);
 
+	if (step->callback_result.attr_handle)
+		free(step->callback_result.attr_handle);
+
 	g_free(step);
 	g_atomic_int_dec_and_test(&scheduled_cbacks_num);
 }
@@ -1652,6 +1687,34 @@ static void gatts_service_deleted_cb(int status, int server_if, int srvc_handle)
 	schedule_callback_verification(step);
 }
 
+static void gatts_request_read_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
+						int attr_handle, int offset,
+						bool is_long)
+{
+	struct step *step = g_new0(struct step, 1);
+	bt_property_t *props[1];
+
+	step->callback = CB_GATTS_REQUEST_READ;
+
+	step->callback_result.conn_id = conn_id;
+	step->callback_result.trans_id = trans_id;
+	step->callback_result.attr_handle = g_memdup(&attr_handle,
+							sizeof(attr_handle));
+	step->callback_result.offset = offset;
+	step->callback_result.is_long = is_long;
+
+	/* Utilize property verification mechanism for bdaddr */
+	props[0] = create_property(BT_PROPERTY_BDADDR, bda, sizeof(*bda));
+
+	step->callback_result.num_properties = 1;
+	step->callback_result.properties = repack_properties(1, props);
+
+	g_free(props[0]->val);
+	g_free(props[0]);
+
+	schedule_callback_verification(step);
+}
+
 static void pan_control_state_cb(btpan_control_state_t state,
 					bt_status_t error, int local_role,
 							const char *ifname)
@@ -1782,7 +1845,7 @@ static const btgatt_server_callbacks_t btgatt_server_callbacks = {
 	.service_started_cb = gatts_service_started_cb,
 	.service_stopped_cb = gatts_service_stopped_cb,
 	.service_deleted_cb = gatts_service_deleted_cb,
-	.request_read_cb = NULL,
+	.request_read_cb = gatts_request_read_cb,
 	.request_write_cb = NULL,
 	.request_exec_write_cb = NULL,
 	.response_confirmation_cb = NULL
diff --git a/android/tester-main.h b/android/tester-main.h
index 31d271a..e710a03 100644
--- a/android/tester-main.h
+++ b/android/tester-main.h
@@ -84,6 +84,14 @@ struct pdu_set {
 		(struct step[]) {__VA_ARGS__}, \
 	}
 
+#define MODIFY_DATA(status, modif_fun, from, to, len) { \
+		.action_status = status, \
+		.action = modif_fun, \
+		.set_data = from, \
+		.set_data_to = to, \
+		.set_data_len = len, \
+	}
+
 #define ACTION(status, act_fun, data_set) { \
 		.action_status = status, \
 		.action = act_fun, \
@@ -318,6 +326,19 @@ struct pdu_set {
 		.callback_result.srvc_handle = cb_srvc_handle, \
 	}
 
+#define CALLBACK_GATTS_REQUEST_READ(cb_conn_id, cb_trans_id, cb_prop, \
+						cb_attr_handle, cb_offset, \
+						cb_is_long) { \
+		.callback = CB_GATTS_REQUEST_READ, \
+		.callback_result.conn_id = cb_conn_id, \
+		.callback_result.trans_id = cb_trans_id, \
+		.callback_result.properties = cb_prop, \
+		.callback_result.num_properties = 1, \
+		.callback_result.attr_handle = cb_attr_handle, \
+		.callback_result.offset = cb_offset, \
+		.callback_result.is_long = cb_is_long, \
+	}
+
 #define CALLBACK_PAN_CTRL_STATE(cb, cb_res, cb_state, cb_local_role) { \
 		.callback = cb, \
 		.callback_result.status = cb_res, \
@@ -471,6 +492,7 @@ typedef enum {
 	CB_EMU_CONNECTION_REJECTED,
 	CB_EMU_VALUE_INDICATION,
 	CB_EMU_VALUE_NOTIFICATION,
+	CB_EMU_READ_RESPONSE,
 } expected_bt_callback_t;
 
 struct test_data {
@@ -568,7 +590,11 @@ struct bt_callback_data {
 
 	int gatt_app_id;
 	int conn_id;
+	int trans_id;
+	int offset;
+	bool is_long;
 	int connected;
+	int *attr_handle;
 	int *srvc_handle;
 	int *inc_srvc_handle;
 	int *char_handle;
@@ -607,6 +633,7 @@ struct step {
 	struct bt_callback_data callback_result;
 
 	void *set_data;
+	void *set_data_to;
 	int set_data_len;
 
 	int *store_srvc_handle;
-- 
1.9.3


^ permalink raw reply related

* [PATCH 8/8] android/tester: Add GATT server send response to write req test cases
From: Grzegorz Kolodziejczyk @ 2014-10-17 13:38 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413553099-19689-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>

This adds send response by server to write request test cases.
---
 android/tester-gatt.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++
 android/tester-main.c |  73 +++++++++++++++++++++++++++-
 android/tester-main.h |  22 +++++++++
 3 files changed, 222 insertions(+), 1 deletion(-)

diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index 6655f2d..f99100d 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -27,6 +27,8 @@
 #define L2CAP_ATT_EXCHANGE_MTU_RSP	0x03
 #define L2CAP_ATT_READ_REQ		0x0a
 #define L2CAP_ATT_READ_RSP		0x0b
+#define L2CAP_ATT_WRITE_REQ		0x12
+#define L2CAP_ATT_WRITE_RSP		0x13
 #define L2CAP_ATT_HANDLE_VALUE_NOTIFY	0x1b
 #define L2CAP_ATT_HANDLE_VALUE_IND	0x1d
 
@@ -54,6 +56,24 @@
 #define GATT_WRITE_TYPE_PREPARE		0x03
 #define GATT_WRITE_TYPE_SIGNED		0x04
 
+#define CHAR_PROP_BROADCAST			0x01
+#define CHAR_PROP_READ				0x02
+#define CHAR_PROP_WRITE_WITHOUT_RESPONSE	0x04
+#define CHAR_PROP_WRITE				0x08
+#define CHAR_PROP_NOTIFY			0x10
+#define CHAR_PROP_INDICATE			0x20
+#define CHAR_PROP_AUTHENTICATED_SIGNED_WRITES	0x40
+#define CHAR_PROP_EXTENDED_PROPERTIES		0x80
+
+#define CHAR_PERM_READ			0x0001
+#define CHAR_PERM_READ_ENCRYPTED	0x0002
+#define CHAR_PERM_READ_ENCRYPTED_MITM	0x0004
+#define CHAR_PERM_WRITE			0x0010
+#define CHAR_PERM_WRITE_ENCRYPTED	0x0020
+#define CHAR_PERM_WRITE_ENCRYPTED_MITM	0x0040
+#define CHAR_PERM_WRITE_SIGNED		0x0080
+#define CHAR_PERM_WRITE_SIGNED_MITM	0x0100
+
 static struct queue *list; /* List of gatt test cases */
 
 static int srvc1_handle;
@@ -66,6 +86,11 @@ struct set_att_data {
 	int len;
 };
 
+struct att_write_req_data {
+	int *attr_handle;
+	uint8_t *value;
+};
+
 static bt_uuid_t app1_uuid = {
 	.uu = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 				0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
@@ -78,6 +103,8 @@ static bt_uuid_t app2_uuid = {
 
 static uint8_t value_1[] = {0x01};
 
+static uint8_t att_write_req_value_1[] = {0x00, 0x01, 0x02, 0x03};
+
 struct gatt_connect_data {
 	const int app_id;
 	const int conn_id;
@@ -521,6 +548,14 @@ static struct add_char_data add_char_data_1 = {
 	.permissions = 0
 };
 
+static struct add_char_data add_char_data_2 = {
+	.app_id = APP1_ID,
+	.srvc_handle = &srvc1_handle,
+	.uuid = &app1_uuid,
+	.properties = CHAR_PROP_WRITE,
+	.permissions = CHAR_PERM_WRITE
+};
+
 static struct add_char_data add_bad_char_data_1 = {
 	.app_id = APP1_ID,
 	.srvc_handle = &srvc_bad_handle,
@@ -774,6 +809,14 @@ static btgatt_response_t response_1 = {
 	.attr_value.offset = 0,
 };
 
+static btgatt_response_t response_2 = {
+	.handle = 0x1c,
+	.attr_value.auth_req = 0,
+	.attr_value.handle = 0x1d,
+	.attr_value.len = sizeof(att_write_req_value_1),
+	.attr_value.offset = 0,
+};
+
 static struct send_resp_data send_resp_data_1 = {
 	.conn_id = CONN1_ID,
 	.trans_id = TRANS1_ID,
@@ -781,6 +824,13 @@ static struct send_resp_data send_resp_data_1 = {
 	.response = &response_1,
 };
 
+static struct send_resp_data send_resp_data_2 = {
+	.conn_id = CONN1_ID,
+	.trans_id = TRANS1_ID,
+	.status = BT_STATUS_SUCCESS,
+	.response = &response_2,
+};
+
 static struct iovec search_service[] = {
 	raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
 	raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),
@@ -1091,8 +1141,15 @@ static struct iovec send_notification_1[] = {
 	end_pdu
 };
 
+static struct att_write_req_data att_write_req_data_1  = {
+	.attr_handle = &char1_handle,
+	.value = att_write_req_value_1,
+};
+
 /* att commands define raw pdus */
 static struct iovec att_read_req = raw_pdu(0x0a, 0x00, 0x00);
+static struct iovec att_write_req_1 = raw_pdu(0x12, 0x00, 0x00, 0x00, 0x00,
+								0x00, 0x00);
 
 static void gatt_att_pdu_modify(void)
 {
@@ -1114,7 +1171,21 @@ static void gatt_att_pdu_modify(void)
 		break;
 	}
 
+	case L2CAP_ATT_WRITE_REQ: {
+		struct att_write_req_data *pdu_set_data =
+						current_data_step->set_data;
+		uint16_t handle = *((int *)(pdu_set_data->attr_handle));
+		uint8_t *value = pdu_set_data->value;
+
+		memcpy(raw_pdu + 1, &handle, sizeof(handle));
+		memcpy(raw_pdu + 3, value, set_data_len - sizeof(handle));
+
+		break;
+	}
 	default:
+		tester_debug("modify att pdu with opcode 0x%02x not handled",
+								raw_pdu[0]);
+
 		break;
 	}
 
@@ -1648,6 +1719,14 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
 
 		schedule_callback_verification(step);
 		break;
+	case L2CAP_ATT_WRITE_RSP:
+		/* TODO - More complicated cases should also verify pdu data */
+		step = g_new0(struct step, 1);
+
+		step->callback = CB_EMU_WRITE_RESPONSE;
+
+		schedule_callback_verification(step);
+		break;
 	default:
 		if (!gatt_pdu || !gatt_pdu->iov_base) {
 			tester_print("Unknown ATT packet.");
@@ -3400,6 +3479,55 @@ static struct test_case test_cases[] = {
 		ACTION_SUCCESS(bluetooth_disable_action, NULL),
 		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
 	),
+	TEST_CASE_BREDRLE("Gatt Server - Send response to write char request",
+		ACTION_SUCCESS(bluetooth_enable_action, NULL),
+		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+		ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+		ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+		ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+		ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
+		CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+		ACTION_SUCCESS(gatt_server_add_service_action,
+							&add_service_data_5),
+		CALLBACK_GATTS_SERVICE_ADDED(GATT_STATUS_SUCCESS, APP1_ID,
+							&service_add_1, NULL,
+							&srvc1_handle),
+		ACTION_SUCCESS(gatt_server_add_char_action, &add_char_data_2),
+		CALLBACK_GATTS_CHARACTERISTIC_ADDED(GATT_STATUS_SUCCESS,
+							APP1_ID, &app1_uuid,
+							&srvc1_handle, NULL,
+							&char1_handle),
+		ACTION_SUCCESS(gatt_server_start_srvc_action,
+							&start_srvc_data_2),
+		CALLBACK_GATTS_SERVICE_STARTED(GATT_STATUS_SUCCESS, APP1_ID,
+								&srvc1_handle),
+		ACTION_SUCCESS(bt_start_discovery_action, NULL),
+		CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+							BT_DISCOVERY_STARTED),
+		CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+		ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+		ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+		CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+						prop_emu_remotes_default_set,
+						CONN1_ID, APP1_ID),
+		MODIFY_DATA(GATT_STATUS_SUCCESS, gatt_att_pdu_modify,
+					&att_write_req_data_1, &att_write_req_1,
+					sizeof(att_write_req_value_1) +
+					ATT_HANDLE_SIZE),
+		ACTION_SUCCESS(gatt_remote_send_raw_pdu_action,
+							&att_write_req_1),
+		CALLBACK_GATTS_REQUEST_WRITE(CONN1_ID, TRANS1_ID,
+						prop_emu_remotes_default_set,
+						&char1_handle, 0,
+						sizeof(att_write_req_value_1),
+						true, false,
+						att_write_req_value_1),
+		ACTION_SUCCESS(gatt_server_send_response_action,
+							&send_resp_data_2),
+		CALLBACK(CB_EMU_WRITE_RESPONSE),
+		ACTION_SUCCESS(bluetooth_disable_action, NULL),
+		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+	),
 };
 
 struct queue *get_gatt_tests(void)
diff --git a/android/tester-main.c b/android/tester-main.c
index e9ebfdd..270be18 100644
--- a/android/tester-main.c
+++ b/android/tester-main.c
@@ -110,6 +110,7 @@ static struct {
 	DBG_CB(CB_EMU_VALUE_INDICATION),
 	DBG_CB(CB_EMU_VALUE_NOTIFICATION),
 	DBG_CB(CB_EMU_READ_RESPONSE),
+	DBG_CB(CB_EMU_WRITE_RESPONSE),
 };
 
 static gboolean check_callbacks_called(gpointer user_data)
@@ -835,6 +836,41 @@ static bool match_data(struct step *step)
 		return false;
 	}
 
+	if (exp->callback_result.length > 0) {
+		if (exp->callback_result.length !=
+						step->callback_result.length) {
+			tester_debug("Gatt attr length mismatch: %d vs %d",
+						exp->callback_result.length,
+						step->callback_result.length);
+			return false;
+		}
+		if (!exp->callback_result.value ||
+						!step->callback_result.value) {
+			tester_debug("Gatt attr values are wrong set");
+			return false;
+		}
+		if (!memcmp(exp->callback_result.value,
+						step->callback_result.value,
+						exp->callback_result.length)) {
+			tester_debug("Gatt attr value mismatch");
+			return false;
+		}
+	}
+
+	if (exp->callback_result.need_rsp != step->callback_result.need_rsp) {
+		tester_debug("Gatt need response value flag mismatch: %d vs %d",
+						exp->callback_result.need_rsp,
+						step->callback_result.need_rsp);
+		return false;
+	}
+
+	if (exp->callback_result.is_prep != step->callback_result.is_prep) {
+		tester_debug("Gatt is prepared value flag mismatch: %d vs %d",
+						exp->callback_result.is_prep,
+						step->callback_result.is_prep);
+		return false;
+	}
+
 	if (exp->store_srvc_handle)
 		memcpy(exp->store_srvc_handle,
 					step->callback_result.srvc_handle,
@@ -966,6 +1002,9 @@ static void destroy_callback_step(void *data)
 	if (step->callback_result.attr_handle)
 		free(step->callback_result.attr_handle);
 
+	if (step->callback_result.value)
+		free(step->callback_result.value);
+
 	g_free(step);
 	g_atomic_int_dec_and_test(&scheduled_cbacks_num);
 }
@@ -1715,6 +1754,38 @@ static void gatts_request_read_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
 	schedule_callback_verification(step);
 }
 
+static void gatts_request_write_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
+						int attr_handle, int offset,
+						int length, bool need_rsp,
+						bool is_prep, uint8_t *value)
+{
+	struct step *step = g_new0(struct step, 1);
+	bt_property_t *props[1];
+
+	step->callback = CB_GATTS_REQUEST_WRITE;
+
+	step->callback_result.conn_id = conn_id;
+	step->callback_result.trans_id = trans_id;
+	step->callback_result.attr_handle = g_memdup(&attr_handle,
+							sizeof(attr_handle));
+	step->callback_result.offset = offset;
+	step->callback_result.length = length;
+	step->callback_result.need_rsp = need_rsp;
+	step->callback_result.is_prep = is_prep;
+	step->callback_result.value = g_memdup(&value, length);
+
+	/* Utilize property verification mechanism for bdaddr */
+	props[0] = create_property(BT_PROPERTY_BDADDR, bda, sizeof(*bda));
+
+	step->callback_result.num_properties = 1;
+	step->callback_result.properties = repack_properties(1, props);
+
+	g_free(props[0]->val);
+	g_free(props[0]);
+
+	schedule_callback_verification(step);
+}
+
 static void pan_control_state_cb(btpan_control_state_t state,
 					bt_status_t error, int local_role,
 							const char *ifname)
@@ -1846,7 +1917,7 @@ static const btgatt_server_callbacks_t btgatt_server_callbacks = {
 	.service_stopped_cb = gatts_service_stopped_cb,
 	.service_deleted_cb = gatts_service_deleted_cb,
 	.request_read_cb = gatts_request_read_cb,
-	.request_write_cb = NULL,
+	.request_write_cb = gatts_request_write_cb,
 	.request_exec_write_cb = NULL,
 	.response_confirmation_cb = NULL
 };
diff --git a/android/tester-main.h b/android/tester-main.h
index e710a03..c938d44 100644
--- a/android/tester-main.h
+++ b/android/tester-main.h
@@ -339,6 +339,23 @@ struct pdu_set {
 		.callback_result.is_long = cb_is_long, \
 	}
 
+#define CALLBACK_GATTS_REQUEST_WRITE(cb_conn_id, cb_trans_id, cb_prop, \
+						cb_attr_handle, cb_offset, \
+						cb_length, cb_need_rsp, \
+						cb_is_prep, cb_value) { \
+		.callback = CB_GATTS_REQUEST_WRITE, \
+		.callback_result.conn_id = cb_conn_id, \
+		.callback_result.trans_id = cb_trans_id, \
+		.callback_result.properties = cb_prop, \
+		.callback_result.num_properties = 1, \
+		.callback_result.attr_handle = cb_attr_handle, \
+		.callback_result.offset = cb_offset, \
+		.callback_result.length = cb_length, \
+		.callback_result.need_rsp = cb_need_rsp, \
+		.callback_result.is_prep = cb_is_prep, \
+		.callback_result.value = cb_value, \
+	}
+
 #define CALLBACK_PAN_CTRL_STATE(cb, cb_res, cb_state, cb_local_role) { \
 		.callback = cb, \
 		.callback_result.status = cb_res, \
@@ -493,6 +510,7 @@ typedef enum {
 	CB_EMU_VALUE_INDICATION,
 	CB_EMU_VALUE_NOTIFICATION,
 	CB_EMU_READ_RESPONSE,
+	CB_EMU_WRITE_RESPONSE,
 } expected_bt_callback_t;
 
 struct test_data {
@@ -608,6 +626,10 @@ struct bt_callback_data {
 	btgatt_notify_params_t *notify_params;
 	int notification_registered;
 	int char_prop;
+	int length;
+	uint8_t *value;
+	bool need_rsp;
+	bool is_prep;
 
 	btpan_control_state_t ctrl_state;
 	btpan_connection_state_t conn_state;
-- 
1.9.3


^ permalink raw reply related

* Re: Locking issue when running out of credits in 6lowpan connection
From: Jukka Rissanen @ 2014-10-17 13:48 UTC (permalink / raw)
  To: Peter Hurley; +Cc: linux-bluetooth, Johan Hedberg, Marcel Holtmann
In-Reply-To: <54411319.7030306@hurleysoftware.com>

On pe, 2014-10-17 at 09:01 -0400, Peter Hurley wrote:
> On 10/17/2014 08:37 AM, Jukka Rissanen wrote:
> > Any ideas how to solve this?
> 
> The spin_lock() in hci_queue_acl() still needs to be spin_lock_bh().

Do'h! Yep, you mentioned that yesterday but I forgot to convert the
locks. Thanks for the help.


Cheers,
Jukka




^ permalink raw reply

* [PATCH 0/3] Avoiding lockdep warnings in 6lowpan
From: Jukka Rissanen @ 2014-10-17 13:56 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

patch 1 changes all rwlocks to RCU as suggested by Peter Hurley.
This should help the performance.

The patch 2 is ported from ieee802154 as suggested by Alex Aring.
This will help avoid lockdep warnings in certain transmit scenarios.

The patch 3 changes normal spin locks to spin_lock_bh() variant when
queueing outgoing packets in hci_queue_acl(). This is needed as packets
coming from 6lowpan link are sent from softirq. Thanks again to
Peter Hurley pointing this out.


Cheers,
Jukka


Jukka Rissanen (3):
  Bluetooth: 6lowpan: Converting rwlocks to use RCU
  Bluetooth: 6lowpan: Fix lockdep splats
  Bluetooth: Wrong style spin lock used

 net/bluetooth/6lowpan.c  | 243 ++++++++++++++++++++++++++++-------------------
 net/bluetooth/hci_core.c |   4 +-
 2 files changed, 149 insertions(+), 98 deletions(-)

-- 
1.8.3.1


^ permalink raw reply

* [PATCH 1/3] Bluetooth: 6lowpan: Converting rwlocks to use RCU
From: Jukka Rissanen @ 2014-10-17 13:56 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413554186-27096-1-git-send-email-jukka.rissanen@linux.intel.com>

The rwlocks are converted to use RCU. This helps performance as the
irq locks are not needed any more.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
---
 net/bluetooth/6lowpan.c | 224 +++++++++++++++++++++++++++---------------------
 1 file changed, 128 insertions(+), 96 deletions(-)

diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index c2e0d14..1fb8e67 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -53,7 +53,7 @@ struct skb_cb {
  * The list contains struct lowpan_dev elements.
  */
 static LIST_HEAD(bt_6lowpan_devices);
-static DEFINE_RWLOCK(devices_lock);
+static DEFINE_SPINLOCK(devices_lock);
 
 /* If psm is set to 0 (default value), then 6lowpan is disabled.
  * Other values are used to indicate a Protocol Service Multiplexer
@@ -67,6 +67,7 @@ static struct l2cap_chan *listen_chan;
 
 struct lowpan_peer {
 	struct list_head list;
+	struct rcu_head rcu;
 	struct l2cap_chan *chan;
 
 	/* peer addresses in various formats */
@@ -86,6 +87,13 @@ struct lowpan_dev {
 	struct delayed_work notify_peers;
 };
 
+static inline void peer_free(struct rcu_head *head)
+{
+	struct lowpan_peer *e = container_of(head, struct lowpan_peer, rcu);
+
+	kfree(e);
+}
+
 static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev)
 {
 	return netdev_priv(netdev);
@@ -93,13 +101,14 @@ static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev)
 
 static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer)
 {
-	list_add(&peer->list, &dev->peers);
+	list_add_rcu(&peer->list, &dev->peers);
 	atomic_inc(&dev->peer_count);
 }
 
 static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer)
 {
-	list_del(&peer->list);
+	list_del_rcu(&peer->list);
+	call_rcu(&peer->rcu, peer_free);
 
 	module_put(THIS_MODULE);
 
@@ -112,33 +121,39 @@ static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer)
 }
 
 static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev,
-						 bdaddr_t *ba, __u8 type)
+						   bdaddr_t *ba, __u8 type)
 {
-	struct lowpan_peer *peer, *tmp;
+	struct lowpan_peer *peer;
 
 	BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count),
 	       ba, type);
 
-	list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(peer, &dev->peers, list) {
 		BT_DBG("dst addr %pMR dst type %d",
 		       &peer->chan->dst, peer->chan->dst_type);
 
 		if (bacmp(&peer->chan->dst, ba))
 			continue;
 
-		if (type == peer->chan->dst_type)
+		if (type == peer->chan->dst_type) {
+			rcu_read_unlock();
 			return peer;
+		}
 	}
 
+	rcu_read_unlock();
+
 	return NULL;
 }
 
-static inline struct lowpan_peer *peer_lookup_chan(struct lowpan_dev *dev,
-						   struct l2cap_chan *chan)
+static inline struct lowpan_peer *__peer_lookup_chan(struct lowpan_dev *dev,
+						     struct l2cap_chan *chan)
 {
-	struct lowpan_peer *peer, *tmp;
+	struct lowpan_peer *peer;
 
-	list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+	list_for_each_entry_rcu(peer, &dev->peers, list) {
 		if (peer->chan == chan)
 			return peer;
 	}
@@ -146,12 +161,12 @@ static inline struct lowpan_peer *peer_lookup_chan(struct lowpan_dev *dev,
 	return NULL;
 }
 
-static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev,
-						   struct l2cap_conn *conn)
+static inline struct lowpan_peer *__peer_lookup_conn(struct lowpan_dev *dev,
+						     struct l2cap_conn *conn)
 {
-	struct lowpan_peer *peer, *tmp;
+	struct lowpan_peer *peer;
 
-	list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+	list_for_each_entry_rcu(peer, &dev->peers, list) {
 		if (peer->chan->conn == conn)
 			return peer;
 	}
@@ -163,7 +178,7 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev,
 						  struct in6_addr *daddr,
 						  struct sk_buff *skb)
 {
-	struct lowpan_peer *peer, *tmp;
+	struct lowpan_peer *peer;
 	struct in6_addr *nexthop;
 	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
 	int count = atomic_read(&dev->peer_count);
@@ -174,9 +189,13 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev,
 	 * send the packet. If only one peer exists, then we can send the
 	 * packet right away.
 	 */
-	if (count == 1)
-		return list_first_entry(&dev->peers, struct lowpan_peer,
-					list);
+	if (count == 1) {
+		rcu_read_lock();
+		peer = list_first_or_null_rcu(&dev->peers, struct lowpan_peer,
+					      list);
+		rcu_read_unlock();
+		return peer;
+	}
 
 	if (!rt) {
 		nexthop = &lowpan_cb(skb)->gw;
@@ -195,53 +214,57 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev,
 
 	BT_DBG("gw %pI6c", nexthop);
 
-	list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(peer, &dev->peers, list) {
 		BT_DBG("dst addr %pMR dst type %d ip %pI6c",
 		       &peer->chan->dst, peer->chan->dst_type,
 		       &peer->peer_addr);
 
-		if (!ipv6_addr_cmp(&peer->peer_addr, nexthop))
+		if (!ipv6_addr_cmp(&peer->peer_addr, nexthop)) {
+			rcu_read_unlock();
 			return peer;
+		}
 	}
 
+	rcu_read_unlock();
+
 	return NULL;
 }
 
 static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
 {
-	struct lowpan_dev *entry, *tmp;
+	struct lowpan_dev *entry;
 	struct lowpan_peer *peer = NULL;
-	unsigned long flags;
 
-	read_lock_irqsave(&devices_lock, flags);
+	rcu_read_lock();
 
-	list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
-		peer = peer_lookup_conn(entry, conn);
+	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
+		peer = __peer_lookup_conn(entry, conn);
 		if (peer)
 			break;
 	}
 
-	read_unlock_irqrestore(&devices_lock, flags);
+	rcu_read_unlock();
 
 	return peer;
 }
 
 static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn)
 {
-	struct lowpan_dev *entry, *tmp;
+	struct lowpan_dev *entry;
 	struct lowpan_dev *dev = NULL;
-	unsigned long flags;
 
-	read_lock_irqsave(&devices_lock, flags);
+	rcu_read_lock();
 
-	list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
 		if (conn->hcon->hdev == entry->hdev) {
 			dev = entry;
 			break;
 		}
 	}
 
-	read_unlock_irqrestore(&devices_lock, flags);
+	rcu_read_unlock();
 
 	return dev;
 }
@@ -271,13 +294,12 @@ static int process_data(struct sk_buff *skb, struct net_device *netdev,
 	u8 iphc0, iphc1;
 	struct lowpan_dev *dev;
 	struct lowpan_peer *peer;
-	unsigned long flags;
 
 	dev = lowpan_dev(netdev);
 
-	read_lock_irqsave(&devices_lock, flags);
-	peer = peer_lookup_chan(dev, chan);
-	read_unlock_irqrestore(&devices_lock, flags);
+	rcu_read_lock();
+	peer = __peer_lookup_chan(dev, chan);
+	rcu_read_unlock();
 	if (!peer)
 		goto drop;
 
@@ -443,7 +465,6 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
 	if (ipv6_addr_is_multicast(&ipv6_daddr)) {
 		lowpan_cb(skb)->chan = NULL;
 	} else {
-		unsigned long flags;
 		u8 addr_type;
 
 		/* Get destination BT device from skb.
@@ -454,19 +475,14 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
 		BT_DBG("dest addr %pMR type %d IP %pI6c", &addr,
 		       addr_type, &ipv6_daddr);
 
-		read_lock_irqsave(&devices_lock, flags);
 		peer = peer_lookup_ba(dev, &addr, addr_type);
-		read_unlock_irqrestore(&devices_lock, flags);
-
 		if (!peer) {
 			/* The packet might be sent to 6lowpan interface
 			 * because of routing (either via default route
 			 * or user set route) so get peer according to
 			 * the destination address.
 			 */
-			read_lock_irqsave(&devices_lock, flags);
 			peer = peer_lookup_dst(dev, &ipv6_daddr, skb);
-			read_unlock_irqrestore(&devices_lock, flags);
 			if (!peer) {
 				BT_DBG("no such peer %pMR found", &addr);
 				return -ENOENT;
@@ -549,14 +565,13 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
 static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct sk_buff *local_skb;
-	struct lowpan_dev *entry, *tmp;
-	unsigned long flags;
+	struct lowpan_dev *entry;
 	int err = 0;
 
-	read_lock_irqsave(&devices_lock, flags);
+	rcu_read_lock();
 
-	list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
-		struct lowpan_peer *pentry, *ptmp;
+	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
+		struct lowpan_peer *pentry;
 		struct lowpan_dev *dev;
 
 		if (entry->netdev != netdev)
@@ -564,7 +579,7 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
 
 		dev = lowpan_dev(entry->netdev);
 
-		list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
+		list_for_each_entry_rcu(pentry, &dev->peers, list) {
 			int ret;
 
 			local_skb = skb_clone(skb, GFP_ATOMIC);
@@ -581,7 +596,7 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
 		}
 	}
 
-	read_unlock_irqrestore(&devices_lock, flags);
+	rcu_read_unlock();
 
 	return err;
 }
@@ -783,7 +798,6 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
 					struct lowpan_dev *dev)
 {
 	struct lowpan_peer *peer;
-	unsigned long flags;
 
 	peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
 	if (!peer)
@@ -806,10 +820,10 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
 	 */
 	set_ip_addr_bits(chan->dst_type, (u8 *)&peer->peer_addr.s6_addr + 8);
 
-	write_lock_irqsave(&devices_lock, flags);
+	spin_lock(&devices_lock);
 	INIT_LIST_HEAD(&peer->list);
 	peer_add(dev, peer);
-	write_unlock_irqrestore(&devices_lock, flags);
+	spin_unlock(&devices_lock);
 
 	/* Notifying peers about us needs to be done without locks held */
 	INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers);
@@ -822,7 +836,6 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
 {
 	struct net_device *netdev;
 	int err = 0;
-	unsigned long flags;
 
 	netdev = alloc_netdev(sizeof(struct lowpan_dev), IFACE_NAME_TEMPLATE,
 			      NET_NAME_UNKNOWN, netdev_setup);
@@ -852,10 +865,10 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
 	(*dev)->hdev = chan->conn->hcon->hdev;
 	INIT_LIST_HEAD(&(*dev)->peers);
 
-	write_lock_irqsave(&devices_lock, flags);
+	spin_lock(&devices_lock);
 	INIT_LIST_HEAD(&(*dev)->list);
-	list_add(&(*dev)->list, &bt_6lowpan_devices);
-	write_unlock_irqrestore(&devices_lock, flags);
+	list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
+	spin_unlock(&devices_lock);
 
 	return 0;
 
@@ -909,11 +922,10 @@ static void delete_netdev(struct work_struct *work)
 
 static void chan_close_cb(struct l2cap_chan *chan)
 {
-	struct lowpan_dev *entry, *tmp;
+	struct lowpan_dev *entry;
 	struct lowpan_dev *dev = NULL;
 	struct lowpan_peer *peer;
 	int err = -ENOENT;
-	unsigned long flags;
 	bool last = false, removed = true;
 
 	BT_DBG("chan %p conn %p", chan, chan->conn);
@@ -928,11 +940,11 @@ static void chan_close_cb(struct l2cap_chan *chan)
 		removed = false;
 	}
 
-	write_lock_irqsave(&devices_lock, flags);
+	spin_lock(&devices_lock);
 
-	list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
 		dev = lowpan_dev(entry->netdev);
-		peer = peer_lookup_chan(dev, chan);
+		peer = __peer_lookup_chan(dev, chan);
 		if (peer) {
 			last = peer_del(dev, peer);
 			err = 0;
@@ -943,13 +955,12 @@ static void chan_close_cb(struct l2cap_chan *chan)
 			       atomic_read(&chan->kref.refcount));
 
 			l2cap_chan_put(chan);
-			kfree(peer);
 			break;
 		}
 	}
 
 	if (!err && last && dev && !atomic_read(&dev->peer_count)) {
-		write_unlock_irqrestore(&devices_lock, flags);
+		spin_unlock(&devices_lock);
 
 		cancel_delayed_work_sync(&dev->notify_peers);
 
@@ -960,7 +971,7 @@ static void chan_close_cb(struct l2cap_chan *chan)
 			schedule_work(&entry->delete_netdev);
 		}
 	} else {
-		write_unlock_irqrestore(&devices_lock, flags);
+		spin_unlock(&devices_lock);
 	}
 
 	return;
@@ -1152,10 +1163,9 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
 
 static void disconnect_all_peers(void)
 {
-	struct lowpan_dev *entry, *tmp_dev;
+	struct lowpan_dev *entry;
 	struct lowpan_peer *peer, *tmp_peer, *new_peer;
 	struct list_head peers;
-	unsigned long flags;
 
 	INIT_LIST_HEAD(&peers);
 
@@ -1164,10 +1174,10 @@ static void disconnect_all_peers(void)
 	 * with the same list at the same time.
 	 */
 
-	read_lock_irqsave(&devices_lock, flags);
+	rcu_read_lock();
 
-	list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) {
-		list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list) {
+	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
+		list_for_each_entry_rcu(peer, &entry->peers, list) {
 			new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC);
 			if (!new_peer)
 				break;
@@ -1179,26 +1189,36 @@ static void disconnect_all_peers(void)
 		}
 	}
 
-	read_unlock_irqrestore(&devices_lock, flags);
+	rcu_read_unlock();
 
+	spin_lock(&devices_lock);
 	list_for_each_entry_safe(peer, tmp_peer, &peers, list) {
 		l2cap_chan_close(peer->chan, ENOENT);
-		kfree(peer);
+
+		list_del_rcu(&peer->list);
+		call_rcu(&peer->rcu, peer_free);
+
+		module_put(THIS_MODULE);
 	}
+	spin_unlock(&devices_lock);
 }
 
-static int lowpan_psm_set(void *data, u64 val)
-{
+struct set_psm {
+	struct work_struct work;
 	u16 psm;
+};
 
-	psm = val;
-	if (psm == 0 || psm_6lowpan != psm)
+static void do_psm_set(struct work_struct *work)
+{
+	struct set_psm *set_psm = container_of(work, struct set_psm, work);
+
+	if (set_psm->psm == 0 || psm_6lowpan != set_psm->psm)
 		/* Disconnect existing connections if 6lowpan is
 		 * disabled (psm = 0), or if psm changes.
 		 */
 		disconnect_all_peers();
 
-	psm_6lowpan = psm;
+	psm_6lowpan = set_psm->psm;
 
 	if (listen_chan) {
 		l2cap_chan_close(listen_chan, 0);
@@ -1207,6 +1227,22 @@ static int lowpan_psm_set(void *data, u64 val)
 
 	listen_chan = bt_6lowpan_listen();
 
+	kfree(set_psm);
+}
+
+static int lowpan_psm_set(void *data, u64 val)
+{
+	struct set_psm *set_psm;
+
+	set_psm = kzalloc(sizeof(*set_psm), GFP_KERNEL);
+	if (!set_psm)
+		return -ENOMEM;
+
+	set_psm->psm = val;
+	INIT_WORK(&set_psm->work, do_psm_set);
+
+	schedule_work(&set_psm->work);
+
 	return 0;
 }
 
@@ -1288,19 +1324,18 @@ static ssize_t lowpan_control_write(struct file *fp,
 
 static int lowpan_control_show(struct seq_file *f, void *ptr)
 {
-	struct lowpan_dev *entry, *tmp_dev;
-	struct lowpan_peer *peer, *tmp_peer;
-	unsigned long flags;
+	struct lowpan_dev *entry;
+	struct lowpan_peer *peer;
 
-	read_lock_irqsave(&devices_lock, flags);
+	spin_lock(&devices_lock);
 
-	list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) {
-		list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list)
+	list_for_each_entry(entry, &bt_6lowpan_devices, list) {
+		list_for_each_entry(peer, &entry->peers, list)
 			seq_printf(f, "%pMR (type %u)\n",
 				   &peer->chan->dst, peer->chan->dst_type);
 	}
 
-	read_unlock_irqrestore(&devices_lock, flags);
+	spin_unlock(&devices_lock);
 
 	return 0;
 }
@@ -1320,9 +1355,8 @@ static const struct file_operations lowpan_control_fops = {
 
 static void disconnect_devices(void)
 {
-	struct lowpan_dev *entry, *tmp, *new_dev;
+	struct lowpan_dev *entry, *new_dev;
 	struct list_head devices;
-	unsigned long flags;
 
 	INIT_LIST_HEAD(&devices);
 
@@ -1331,9 +1365,9 @@ static void disconnect_devices(void)
 	 * devices list.
 	 */
 
-	read_lock_irqsave(&devices_lock, flags);
+	rcu_read_lock();
 
-	list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
 		new_dev = kmalloc(sizeof(*new_dev), GFP_ATOMIC);
 		if (!new_dev)
 			break;
@@ -1341,12 +1375,12 @@ static void disconnect_devices(void)
 		new_dev->netdev = entry->netdev;
 		INIT_LIST_HEAD(&new_dev->list);
 
-		list_add(&new_dev->list, &devices);
+		list_add_rcu(&new_dev->list, &devices);
 	}
 
-	read_unlock_irqrestore(&devices_lock, flags);
+	rcu_read_unlock();
 
-	list_for_each_entry_safe(entry, tmp, &devices, list) {
+	list_for_each_entry(entry, &devices, list) {
 		ifdown(entry->netdev);
 		BT_DBG("Unregistering netdev %s %p",
 		       entry->netdev->name, entry->netdev);
@@ -1359,17 +1393,15 @@ static int device_event(struct notifier_block *unused,
 			unsigned long event, void *ptr)
 {
 	struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
-	struct lowpan_dev *entry, *tmp;
-	unsigned long flags;
+	struct lowpan_dev *entry;
 
 	if (netdev->type != ARPHRD_6LOWPAN)
 		return NOTIFY_DONE;
 
 	switch (event) {
 	case NETDEV_UNREGISTER:
-		write_lock_irqsave(&devices_lock, flags);
-		list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices,
-					 list) {
+		spin_lock(&devices_lock);
+		list_for_each_entry(entry, &bt_6lowpan_devices, list) {
 			if (entry->netdev == netdev) {
 				BT_DBG("Unregistered netdev %s %p",
 				       netdev->name, netdev);
@@ -1378,7 +1410,7 @@ static int device_event(struct notifier_block *unused,
 				break;
 			}
 		}
-		write_unlock_irqrestore(&devices_lock, flags);
+		spin_unlock(&devices_lock);
 		break;
 	}
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH 2/3] Bluetooth: 6lowpan: Fix lockdep splats
From: Jukka Rissanen @ 2014-10-17 13:56 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1413554186-27096-1-git-send-email-jukka.rissanen@linux.intel.com>

When a device ndo_start_xmit() calls again dev_queue_xmit(),
lockdep can complain because dev_queue_xmit() is re-entered and the
spinlocks protecting tx queues share a common lockdep class.

Same issue was fixed for ieee802162 in commit "20e7c4e80dcd"

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
---
 net/bluetooth/6lowpan.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 1fb8e67..b407457 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -653,7 +653,26 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
 	return err < 0 ? NET_XMIT_DROP : err;
 }
 
+static struct lock_class_key bt_tx_busylock;
+static struct lock_class_key bt_netdev_xmit_lock_key;
+
+static void bt_set_lockdep_class_one(struct net_device *dev,
+				     struct netdev_queue *txq,
+				     void *_unused)
+{
+	lockdep_set_class(&txq->_xmit_lock, &bt_netdev_xmit_lock_key);
+}
+
+static int bt_dev_init(struct net_device *dev)
+{
+	netdev_for_each_tx_queue(dev, bt_set_lockdep_class_one, NULL);
+	dev->qdisc_tx_busylock = &bt_tx_busylock;
+
+	return 0;
+}
+
 static const struct net_device_ops netdev_ops = {
+	.ndo_init		= bt_dev_init,
 	.ndo_start_xmit		= bt_xmit,
 };
 
-- 
1.8.3.1


^ 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