Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 01/12] Bluetooth: Add automated SSP user confirmation responses
From: johan.hedberg @ 2011-04-28 18:28 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@nokia.com>

This patch adds automated negative and positive (auto-accept) responses
for Secure Simple Pairing user confirmation requests. The responses are
only sent if the HCI_MGMT flag is set in order not to confuse older user
space versions (without management interface support).

Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
---
 net/bluetooth/hci_event.c |   37 +++++++++++++++++++++++++++++++++++--
 1 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 577d638..514e10e 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2483,14 +2483,47 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
 							struct sk_buff *skb)
 {
 	struct hci_ev_user_confirm_req *ev = (void *) skb->data;
+	int loc_mitm, rem_mitm;
+	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
 	hci_dev_lock(hdev);
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
-		mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey);
+	if (!test_bit(HCI_MGMT, &hdev->flags))
+		goto unlock;
 
+	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+	if (!conn)
+		goto unlock;
+
+	loc_mitm = (conn->auth_type & 0x01);
+	rem_mitm = (conn->remote_auth & 0x01);
+
+	/* If we require MITM but the remote device can't provide that
+	 * (it has NoInputNoOutput) then reject the confirmation
+	 * request. The only exception is when we're dedicated bonding
+	 * initiators (connect_cfm_cb set) since then we always have the MITM
+	 * bit set. */
+	if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) {
+		BT_DBG("Rejecting request: remote device can't provide MITM");
+		hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
+					sizeof(ev->bdaddr), &ev->bdaddr);
+		goto unlock;
+	}
+
+	/* If no side requires MITM protection; auto-accept */
+	if ((!loc_mitm || conn->remote_cap == 0x03) &&
+				(!rem_mitm || conn->io_capability == 0x03)) {
+		BT_DBG("Auto-accept of user confirmation");
+		hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY,
+						sizeof(ev->bdaddr), &ev->bdaddr);
+		goto unlock;
+	}
+
+	mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey);
+
+unlock:
 	hci_dev_unlock(hdev);
 }
 
-- 
1.7.4.4


^ permalink raw reply related

* Re: [PATCH v3 5/7] Bluetooth: Double check sec req for pre 2.1 device
From: Johan Hedberg @ 2011-04-28 18:11 UTC (permalink / raw)
  To: Waldemar Rymarkiewicz; +Cc: padovan, linux-bluetooth
In-Reply-To: <1303985279-3944-6-git-send-email-waldemar.rymarkiewicz@tieto.com>

Hi Waldek,

On Thu, Apr 28, 2011, Waldemar Rymarkiewicz wrote:
> +static int rfcomm_accept_secure(struct hci_conn *conn, struct rfcomm_dlc *d)
> +{
> +	BT_DBG("");
> +
> +	if (d->sec_level != BT_SECURITY_HIGH)
> +		return 1; /* Accept */
> +
> +	if (conn->key_type == HCI_LK_AUTH_COMBINATION ||
> +			(conn->key_type == HCI_LK_COMBINATION &&
> +			conn->pin_length == 16))
> +		return 1;
> +
> +	return 0; /* Reject */
> +}

If conn->key_type and conn->pin_length are like you want them to be in
the second if-statement, shouldn't conn->sec_level already be
BT_SECURITY_HIGH? And if that's the case I guess you don't need a
separate function at all: just check for conn->sec_level. Btw, what
purpose does d->sec_level serve when we already have conn->sec_level?

Johan

^ permalink raw reply

* Re: [PATCH v3 5/7] Bluetooth: Double check sec req for pre 2.1 device
From: Gustavo F. Padovan @ 2011-04-28 18:09 UTC (permalink / raw)
  To: Waldemar Rymarkiewicz; +Cc: Johan Hedberg, linux-bluetooth
In-Reply-To: <1303985279-3944-6-git-send-email-waldemar.rymarkiewicz@tieto.com>

Hi Waldermar,

* Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> [2011-04-28 12:07:57 +0200]:

> In case of pre v2.1 devices authentication request will return
> success immediately if the link key already exists without any
> authentication process.
> 
> That means, it's not possible to re-authenticate the link if you
> already have combination key and for instance want to re-authenticate
> to get the high security (use 16 digit pin).
> 
> Therefore, it's necessary to check security requirements on auth
> complete event to prevent not enough secure connection.
> 
> Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
> ---
>  net/bluetooth/rfcomm/core.c |   17 ++++++++++++++++-
>  1 files changed, 16 insertions(+), 1 deletions(-)
> 
> diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
> index 121a5c1..676fdec 100644
> --- a/net/bluetooth/rfcomm/core.c
> +++ b/net/bluetooth/rfcomm/core.c
> @@ -2057,6 +2057,21 @@ static int rfcomm_run(void *unused)
>  	return 0;
>  }
>  
> +static int rfcomm_accept_secure(struct hci_conn *conn, struct rfcomm_dlc *d)
> +{
> +	BT_DBG("");
> +
> +	if (d->sec_level != BT_SECURITY_HIGH)
> +		return 1; /* Accept */
> +
> +	if (conn->key_type == HCI_LK_AUTH_COMBINATION ||
> +			(conn->key_type == HCI_LK_COMBINATION &&
> +			conn->pin_length == 16))
> +		return 1;
> +
> +	return 0; /* Reject */
> +}

I don't like the idea of mix HCI and RFCOMM code, I prefer that you create an
hci_accept_secure(conn, d->sec_level) instead.

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: latest bluetooth-next doesn't compile
From: Gustavo F. Padovan @ 2011-04-28 14:35 UTC (permalink / raw)
  To: Mika Linnanoja; +Cc: linux-bluetooth, Ville Tervo
In-Reply-To: <4DB94EB2.5060204@nokia.com>

Hi Mika,

* Mika Linnanoja <mika.linnanoja@nokia.com> [2011-04-28 14:25:38 +0300]:

> Hi!
> 
> I cloned today 
> git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6.git 
> and seems it does not want to fully compile.
> 
> Steps were like this:
> $ git clone <url>
> $ cd <git_dir>
> $ cp /boot/old_config_file .config
> $ make oldconfig (default answers)
> $ make
>    CHK     include/linux/version.h
>    CHK     include/generated/utsrelease.h
>    CALL    scripts/checksyscalls.sh
>    CHK     include/generated/compile.h
>    UPD     include/generated/compile.h
>    CC      init/version.o
>    LD      init/built-in.o
>    VDSOSYM arch/x86/vdso/vdso32-int80-syms.lds
>    VDSOSYM arch/x86/vdso/vdso32-sysenter-syms.lds
>    VDSOSYM arch/x86/vdso/vdso32-syms.lds
>    LD      arch/x86/vdso/built-in.o
>    LD      arch/x86/built-in.o
>    CC [M]  net/bluetooth/cmtp/core.o
> net/bluetooth/cmtp/core.c: In function ‘cmtp_add_connection’:
> net/bluetooth/cmtp/core.c:349: error: ‘struct l2cap_pinfo’ has no member named 
> ‘omtu’
> net/bluetooth/cmtp/core.c:349: error: ‘struct l2cap_pinfo’ has no member named 
> ‘imtu’
> make[3]: *** [net/bluetooth/cmtp/core.o] Error 1
> make[2]: *** [net/bluetooth/cmtp] Error 2
> make[1]: *** [net/bluetooth] Error 2
> make: *** [net] Error 2
> $
> 
> Is this a known issue? I have not tried to build this exact tree before.

linux-next spotted this to me yesterday. I fixed it already. I didn't have
CONFIG_HID and CONFIG_ISDN_CAPI enabled so I was unable to see this. Sorry.

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: btusb not working in 2.6.38.4
From: Greg KH @ 2011-04-28 13:21 UTC (permalink / raw)
  To: Andrej Podzimek, linux-bluetooth, stable
In-Reply-To: <20110428051124.GC2214@joana>

On Thu, Apr 28, 2011 at 02:11:24AM -0300, Gustavo F. Padovan wrote:
> Hi Andrej,
> 
> * Andrej Podzimek <andrej@podzimek.org> [2011-04-28 01:22:02 +0200]:
> 
> > Hello,
> > 
> > after a recent kernel update on Arch Linux (2.6.38.4), I can see the following problem in dmesg:
> > 
> > ------------[ cut here ]------------
> > WARNING: at lib/kobject.c:595 kobject_put+0x40/0x50()
> > Hardware name: To Be Filled By O.E.M.
> > kobject: '(null)' (ffff88023f60d5a0): is not initialized, yet kobject_put() is being called.
> > Modules linked in: btusb(+) bluetooth rfkill usbhid hid button i2c_i801 i2c_core r8169 mii iTCO_wdt iTCO_vendor_support psmouse sg serio_raw evdev pcspkr ip_tables ip6_tables x_tables tpm_tis tpm tpm_bios w83627ehf hwmon_vid coretemp ext4 mbcache jbd2 crc16 dm_mod usb_storage raid456 async_raid6_recov async_pq raid6_pq async_xor xor async_memcpy async_tx md_mod uhci_hcd xhci_hcd ehci_hcd usbcore sd_mod crc_t10dif ahci libahci libata scsi_mod cpufreq_ondemand acpi_cpufreq freq_table processor mperf i7core_edac edac_core
> > Pid: 1820, comm: modprobe Not tainted 2.6.38-ARCH #1
> > Call Trace:
> >   [<ffffffff8103a86b>] ? warn_slowpath_common+0x7b/0xc0
> >   [<ffffffff8103a965>] ? warn_slowpath_fmt+0x45/0x50
> >   [<ffffffff81248d3f>] ? skb_dequeue+0x5f/0x80
> >   [<ffffffff8116b6f0>] ? kobject_put+0x40/0x50
> >   [<ffffffffa025f85c>] ? btusb_probe+0x57c/0x5e0 [btusb]
> >   [<ffffffffa00b85d5>] ? usb_probe_interface+0xe5/0x1e0 [usbcore]
> >   [<ffffffff81215aaf>] ? driver_probe_device+0x6f/0x190
> >   [<ffffffff81215c63>] ? __driver_attach+0x93/0xa0
> >   [<ffffffff81215bd0>] ? __driver_attach+0x0/0xa0
> >   [<ffffffff81214b23>] ? bus_for_each_dev+0x53/0x80
> >   [<ffffffff812153f8>] ? bus_add_driver+0x188/0x260
> >   [<ffffffff81215e3a>] ? driver_register+0x6a/0x130
> >   [<ffffffffa00b748a>] ? usb_register_driver+0x8a/0x180 [usbcore]
> >   [<ffffffffa011c000>] ? btusb_init+0x0/0x1000 [btusb]
> >   [<ffffffff810001dc>] ? do_one_initcall+0x3c/0x170
> >   [<ffffffff8106db3a>] ? sys_init_module+0xda/0x230
> >   [<ffffffff8100243b>] ? system_call_fastpath+0x16/0x1b
> > ---[ end trace 9c4648061ddb0b67 ]---
> > 
> > Presumably, Bluetooth does not seem to work at all (i.e., hciconfig -a does not output anything).
> > 
> > The output from lsusb -v relevant to the specific device is attached.
> > 
> > The device worked 100% flawlessly with 2.6.38.3. I had an a2dp headset and a mouse paired with it, both of which worked perfectly fine in parallel.
> 
> The only Bluetooth change in 2.6.38.4 is: https://lkml.org/lkml/2011/4/19/406
> However I don't think this patch is causing this issue. Do you care to patch -R it
> and test?
> If the problem is somewhere else we have to go with a bisect, there are only
> 70 patches, so it shouldn't take to long.
> 
> Greg, any idea on that? Are there similar reports of warnings for 2.6.38.4?

No, I have not seen any reported warnings like this.  A 'git bisect'
should be quick to do to find the offending patch.

thanks,

greg k-h

^ permalink raw reply

* [PATCH] Bluetooth: Allow unsegmented SDU retries on sock_queue_rcv_skb failure.
From: Ruiyi Zhang @ 2011-04-28 11:39 UTC (permalink / raw)
  To: padovan; +Cc: linux-bluetooth, Ruiyi Zhang

 In L2CAP_SDU_UNSEGMENTED case, if sock_queue_rcv_skb returns error,
 l2cap_ertm_reassembly_sdu should not return 0 so as to insert the
 skb into BUSY_QUEUE for later retries.


Signed-off-by: Ruiyi Zhang <Ruiyi.zhang@atheros.com>
---
 net/bluetooth/l2cap_core.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ca27f3a..3b2f140 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2784,8 +2784,7 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
 			goto drop;
 
 		err = sock_queue_rcv_skb(sk, skb);
-		if (!err)
-			return err;
+		return err;
 
 		break;
 
-- 
1.7.1


^ permalink raw reply related

* [PATCH] Bluetooth: Allow unsegmented SDU retries on sock_queue_rcv_skb failure. In L2CAP_SDU_UNSEGMENTED case, if sock_queue_rcv_skb returns error, l2cap_ertm_reassembly_sdu should not return 0 so as to insert the skb into BUSY_QUEUE for later retries.
From: Ruiyi Zhang @ 2011-04-28 11:31 UTC (permalink / raw)
  To: padovan; +Cc: linux-bluetooth, Ruiyi Zhang


Signed-off-by: Ruiyi Zhang <Ruiyi.zhang@atheros.com>
---
 net/bluetooth/l2cap_core.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ca27f3a..3b2f140 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2784,8 +2784,7 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
 			goto drop;
 
 		err = sock_queue_rcv_skb(sk, skb);
-		if (!err)
-			return err;
+		return err;
 
 		break;
 
-- 
1.7.1


^ permalink raw reply related

* latest bluetooth-next doesn't compile
From: Mika Linnanoja @ 2011-04-28 11:25 UTC (permalink / raw)
  To: padovan; +Cc: linux-bluetooth, Ville Tervo

Hi!

I cloned today 
git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next-2.6.git 
and seems it does not want to fully compile.

Steps were like this:
$ git clone <url>
$ cd <git_dir>
$ cp /boot/old_config_file .config
$ make oldconfig (default answers)
$ make
   CHK     include/linux/version.h
   CHK     include/generated/utsrelease.h
   CALL    scripts/checksyscalls.sh
   CHK     include/generated/compile.h
   UPD     include/generated/compile.h
   CC      init/version.o
   LD      init/built-in.o
   VDSOSYM arch/x86/vdso/vdso32-int80-syms.lds
   VDSOSYM arch/x86/vdso/vdso32-sysenter-syms.lds
   VDSOSYM arch/x86/vdso/vdso32-syms.lds
   LD      arch/x86/vdso/built-in.o
   LD      arch/x86/built-in.o
   CC [M]  net/bluetooth/cmtp/core.o
net/bluetooth/cmtp/core.c: In function ‘cmtp_add_connection’:
net/bluetooth/cmtp/core.c:349: error: ‘struct l2cap_pinfo’ has no member named 
‘omtu’
net/bluetooth/cmtp/core.c:349: error: ‘struct l2cap_pinfo’ has no member named 
‘imtu’
make[3]: *** [net/bluetooth/cmtp/core.o] Error 1
make[2]: *** [net/bluetooth/cmtp] Error 2
make[1]: *** [net/bluetooth] Error 2
make: *** [net] Error 2
$

Is this a known issue? I have not tried to build this exact tree before.

BR,
Mika

^ permalink raw reply

* [PATCH 2/2] Add support of secure pin code in mgmt code
From: Waldemar Rymarkiewicz @ 2011-04-28 10:50 UTC (permalink / raw)
  To: linux-bluetooth, Johan Hedberg; +Cc: Waldemar Rymarkiewicz
In-Reply-To: <1303987847-6878-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

Use secure pin code parameter received from the kernel in
MGMT_EV_PIN_CODE_REQUEST event and propagate this to agent
code.

The secure flag is saved in the device structure not to change
common interface for all authentication types. Secure flag is
specific for the pin code request only.
---
 plugins/hciops.c  |    5 ++++-
 plugins/mgmtops.c |    2 +-
 src/agent.c       |   10 ++++++++--
 src/device.c      |   17 +++++++++++++++++
 src/device.h      |    2 ++
 src/event.c       |   17 +++++++++++++++--
 src/event.h       |    2 +-
 7 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/plugins/hciops.c b/plugins/hciops.c
index 2b9be3f..a9296be 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -1244,6 +1244,7 @@ static void pin_code_request(int index, bdaddr_t *dba)
 	struct bt_conn *conn;
 	char addr[18];
 	int err;
+	uint8_t secure = 0;
 
 	ba2str(dba, addr);
 	DBG("hci%d PIN request for %s", index, addr);
@@ -1259,7 +1260,9 @@ static void pin_code_request(int index, bdaddr_t *dba)
 		goto reject;
 	}
 
-	err = btd_event_request_pin(&dev->bdaddr, dba);
+	/*TODO check if we need secure pin */
+
+	err = btd_event_request_pin(&dev->bdaddr, dba, secure);
 	if (err < 0) {
 		error("PIN code negative reply: %s", strerror(-err));
 		goto reject;
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index bb53e82..869ffd2 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -565,7 +565,7 @@ static void mgmt_pin_code_request(int sk, uint16_t index, void *buf, size_t len)
 
 	info = &controllers[index];
 
-	err = btd_event_request_pin(&info->bdaddr, &ev->bdaddr);
+	err = btd_event_request_pin(&info->bdaddr, &ev->bdaddr, ev->secure);
 	if (err < 0) {
 		error("btd_event_request_pin: %s", strerror(-err));
 		mgmt_pincode_reply(index, &ev->bdaddr, NULL);
diff --git a/src/agent.c b/src/agent.c
index f87f253..d7b5f46 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -424,10 +424,13 @@ done:
 }
 
 static int pincode_request_new(struct agent_request *req, const char *device_path,
-				dbus_bool_t numeric)
+				uint8_t secure)
 {
 	struct agent *agent = req->agent;
 
+	/* TODO: Add a new method or a new param to Agent interface to request
+		secure pin. */
+
 	req->msg = dbus_message_new_method_call(agent->name, agent->path,
 					"org.bluez.Agent", "RequestPinCode");
 	if (req->msg == NULL) {
@@ -455,14 +458,17 @@ int agent_request_pincode(struct agent *agent, struct btd_device *device,
 	struct agent_request *req;
 	const gchar *dev_path = device_get_path(device);
 	int err;
+	uint8_t secure;
 
 	if (agent->request)
 		return -EBUSY;
 
+	secure = device_get_secure_pin(device);
+
 	req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb,
 							user_data, destroy);
 
-	err = pincode_request_new(req, dev_path, FALSE);
+	err = pincode_request_new(req, dev_path, secure);
 	if (err < 0)
 		goto failed;
 
diff --git a/src/device.c b/src/device.c
index b0a6542..dc872ca 100644
--- a/src/device.c
+++ b/src/device.c
@@ -136,6 +136,8 @@ struct btd_device {
 	gboolean	paired;
 	gboolean	blocked;
 
+	uint8_t		secure_pin;
+
 	gboolean	authorizing;
 	gint		ref;
 };
@@ -1776,6 +1778,21 @@ struct agent *device_get_agent(struct btd_device *device)
 	return adapter_get_agent(device->adapter);
 }
 
+uint8_t device_get_secure_pin(struct btd_device *device)
+{
+	return device->secure_pin;
+}
+
+void device_set_secure_pin(struct btd_device *device, uint8_t secure)
+{
+	if (!device)
+		return;
+
+	DBG("secure pin %d", secure);
+
+	device->secure_pin = secure;
+}
+
 gboolean device_is_busy(struct btd_device *device)
 {
 	return device->browse ? TRUE : FALSE;
diff --git a/src/device.h b/src/device.h
index d59b8eb..5e70379 100644
--- a/src/device.h
+++ b/src/device.h
@@ -65,6 +65,8 @@ struct btd_adapter *device_get_adapter(struct btd_device *device);
 void device_get_address(struct btd_device *device, bdaddr_t *bdaddr);
 const gchar *device_get_path(struct btd_device *device);
 struct agent *device_get_agent(struct btd_device *device);
+uint8_t device_get_secure_pin(struct btd_device *device);
+void device_set_secure_pin(struct btd_device *device, uint8_t secure);
 gboolean device_is_busy(struct btd_device *device);
 gboolean device_is_temporary(struct btd_device *device);
 gboolean device_is_paired(struct btd_device *device);
diff --git a/src/event.c b/src/event.c
index 5373e33..d6185a6 100644
--- a/src/event.c
+++ b/src/event.c
@@ -106,6 +106,8 @@ static void pincode_cb(struct agent *agent, DBusError *derr,
 {
 	struct btd_adapter *adapter = device_get_adapter(device);
 	bdaddr_t dba;
+	size_t pin_len;
+	uint8_t secure;
 	int err;
 
 	device_get_address(device, &dba);
@@ -117,6 +119,15 @@ static void pincode_cb(struct agent *agent, DBusError *derr,
 		return;
 	}
 
+	pin_len = strlen(pincode);
+	secure  = device_get_secure_pin(device);
+
+	if (secure && pin_len != 16) {
+		err = btd_adapter_pincode_reply(adapter, &dba, NULL);
+		if (err < 0)
+			goto fail;
+	}
+
 	err = btd_adapter_pincode_reply(adapter, &dba, pincode);
 	if (err < 0)
 		goto fail;
@@ -127,7 +138,7 @@ fail:
 	error("Sending PIN code reply failed: %s (%d)", strerror(-err), -err);
 }
 
-int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba)
+int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba, uint8_t secure)
 {
 	struct btd_adapter *adapter;
 	struct btd_device *device;
@@ -139,11 +150,13 @@ int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba)
 
 	memset(pin, 0, sizeof(pin));
 	pinlen = read_pin_code(sba, dba, pin);
-	if (pinlen > 0) {
+	if (pinlen > 0 && (secure && pinlen == 16)) {
 		btd_adapter_pincode_reply(adapter, dba, pin);
 		return 0;
 	}
 
+	device_set_secure_pin(device, secure);
+
 	return device_request_authentication(device, AUTH_TYPE_PINCODE, 0,
 								pincode_cb);
 }
diff --git a/src/event.h b/src/event.h
index 765390a..865da63 100644
--- a/src/event.h
+++ b/src/event.h
@@ -22,7 +22,7 @@
  *
  */
 
-int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba);
+int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba, uint8_t secure);
 void btd_event_advertising_report(bdaddr_t *local, le_advertising_info *info);
 void btd_event_device_found(bdaddr_t *local, bdaddr_t *peer, uint32_t class,
 						int8_t rssi, uint8_t *data);
-- 
1.7.1


^ permalink raw reply related

* [PATCH 1/2] Add secure param to Mgmt PIN Code Request Event
From: Waldemar Rymarkiewicz @ 2011-04-28 10:50 UTC (permalink / raw)
  To: linux-bluetooth, Johan Hedberg; +Cc: Waldemar Rymarkiewicz

Update mgmt interface with secure param in pin code request event
which is part of secure pin requirement implementation.
---
 doc/mgmt-api.txt |    1 +
 lib/mgmt.h       |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index 925b5ad..45f6a64 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -482,6 +482,7 @@ PIN Code Request Event
 Event Code		0x000E
 Controller Index:	<controller id>
 Event Parameters	Address (6 Octets)
+			Secure (1 Octet)
 
 
 User Confirmation Request Event
diff --git a/lib/mgmt.h b/lib/mgmt.h
index f45321c..b1f71ee 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -259,6 +259,7 @@ struct mgmt_ev_connect_failed {
 #define MGMT_EV_PIN_CODE_REQUEST	0x000E
 struct mgmt_ev_pin_code_request {
 	bdaddr_t bdaddr;
+	uint8_t secure;
 } __packed;
 
 #define MGMT_EV_USER_CONFIRM_REQUEST	0x000F
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3 7/7] Bluetooth: Add secure flag for mgmt_pin_code_req
From: Waldemar Rymarkiewicz @ 2011-04-28 10:07 UTC (permalink / raw)
  To: Johan Hedberg, padovan; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
In-Reply-To: <1303985279-3944-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

Extend the mgmt_pin_code_request interface to require secure
pin code (16 digit) for authentication.

This is a kernel part of the secure pin code requirement notification
to user space agent.

Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
---
 include/net/bluetooth/hci_core.h |    2 +-
 include/net/bluetooth/mgmt.h     |    1 +
 net/bluetooth/hci_event.c        |    9 +++++++--
 net/bluetooth/mgmt.c             |    3 ++-
 4 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 2da2eb9..2995e2e 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -777,7 +777,7 @@ int mgmt_connected(u16 index, bdaddr_t *bdaddr);
 int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
 int mgmt_disconnect_failed(u16 index);
 int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
+int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure);
 int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
 int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
 int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 7434406..0e7de63 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -253,6 +253,7 @@ struct mgmt_ev_connect_failed {
 #define MGMT_EV_PIN_CODE_REQUEST	0x000E
 struct mgmt_ev_pin_code_request {
 	bdaddr_t bdaddr;
+	__u8 secure;
 } __packed;
 
 #define MGMT_EV_USER_CONFIRM_REQUEST	0x000F
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 9d50e90..5350ad0 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2006,6 +2006,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
 {
 	struct hci_ev_pin_code_req *ev = (void *) skb->data;
 	struct hci_conn *conn;
+	u8 secure = 0;
 
 	BT_DBG("%s", hdev->name);
 
@@ -2022,8 +2023,12 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
 		hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
 					sizeof(ev->bdaddr), &ev->bdaddr);
 
-	if (test_bit(HCI_MGMT, &hdev->flags))
-		mgmt_pin_code_request(hdev->id, &ev->bdaddr);
+	if (test_bit(HCI_MGMT, &hdev->flags)) {
+		if (conn->pending_sec_level == BT_SECURITY_HIGH)
+			secure = 1;
+
+		mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
+	}
 
 	hci_dev_unlock(hdev);
 }
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4542396..a7b4937 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1942,11 +1942,12 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
 	return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr)
+int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
 {
 	struct mgmt_ev_pin_code_request ev;
 
 	bacpy(&ev.bdaddr, bdaddr);
+	ev.secure = secure;
 
 	return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
 									NULL);
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3 6/7] Bluetooth: Respect local MITM req in io_cap reply
From: Waldemar Rymarkiewicz @ 2011-04-28 10:07 UTC (permalink / raw)
  To: Johan Hedberg, padovan; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
In-Reply-To: <1303985279-3944-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

If host requires MITM protection notify that to controller in
io capabilities reply even if the remote device requires no bonding.

If it is not respected, host can get an unauthenticated link key while
it expects authenticated one.

Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
---
 net/bluetooth/hci_event.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 40e96cd..9d50e90 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2397,7 +2397,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn)
 
 	/* If remote requests no-bonding follow that lead */
 	if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01)
-		return 0x00;
+		return conn->remote_auth | (conn->auth_type & 0x01);
 
 	return conn->auth_type;
 }
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3 5/7] Bluetooth: Double check sec req for pre 2.1 device
From: Waldemar Rymarkiewicz @ 2011-04-28 10:07 UTC (permalink / raw)
  To: Johan Hedberg, padovan; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
In-Reply-To: <1303985279-3944-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

In case of pre v2.1 devices authentication request will return
success immediately if the link key already exists without any
authentication process.

That means, it's not possible to re-authenticate the link if you
already have combination key and for instance want to re-authenticate
to get the high security (use 16 digit pin).

Therefore, it's necessary to check security requirements on auth
complete event to prevent not enough secure connection.

Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
---
 net/bluetooth/rfcomm/core.c |   17 ++++++++++++++++-
 1 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 121a5c1..676fdec 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -2057,6 +2057,21 @@ static int rfcomm_run(void *unused)
 	return 0;
 }
 
+static int rfcomm_accept_secure(struct hci_conn *conn, struct rfcomm_dlc *d)
+{
+	BT_DBG("");
+
+	if (d->sec_level != BT_SECURITY_HIGH)
+		return 1; /* Accept */
+
+	if (conn->key_type == HCI_LK_AUTH_COMBINATION ||
+			(conn->key_type == HCI_LK_COMBINATION &&
+			conn->pin_length == 16))
+		return 1;
+
+	return 0; /* Reject */
+}
+
 static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
 {
 	struct rfcomm_session *s;
@@ -2096,7 +2111,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
 		if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
 			continue;
 
-		if (!status)
+		if (!status && rfcomm_accept_secure(conn, d))
 			set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
 		else
 			set_bit(RFCOMM_AUTH_REJECT, &d->flags);
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3 4/7] Bluetooth: Ignore key unauthenticated for high security
From: Waldemar Rymarkiewicz @ 2011-04-28 10:07 UTC (permalink / raw)
  To: Johan Hedberg, padovan; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
In-Reply-To: <1303985279-3944-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

High security level for pre v2.1 devices requires combination link key
authenticated by at least 16 digit PIN code.

It's also necessary to update key_type and pin_length when the key
exists and is sufficently secured for the connection as there will be
no link key notify event in that case.

Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
---
 net/bluetooth/hci_event.c |   20 ++++++++++++++++----
 1 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 655af8b..40e96cd 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2059,11 +2059,23 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
 	}
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+	if (conn) {
+		if (key->type == HCI_LK_UNAUTH_COMBINATION &&
+				conn->auth_type != 0xff &&
+				(conn->auth_type & 0x01)) {
+			BT_DBG("%s ignoring unauthenticated key", hdev->name);
+			goto not_found;
+		}
 
-	if (key->type == HCI_LK_UNAUTH_COMBINATION && conn &&
-			conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
-		BT_DBG("%s ignoring unauthenticated key", hdev->name);
-		goto not_found;
+		if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
+				conn->pending_sec_level == BT_SECURITY_HIGH) {
+			BT_DBG("%s ignoring key unauthenticated for high \
+							security", hdev->name);
+			goto not_found;
+		}
+
+		conn->key_type = key->type;
+		conn->pin_length = key->pin_len;
 	}
 
 	bacpy(&cp.bdaddr, &ev->bdaddr);
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3 3/7] Bluetooth: Map sec_level to link key requirements
From: Waldemar Rymarkiewicz @ 2011-04-28 10:07 UTC (permalink / raw)
  To: Johan Hedberg, padovan; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
In-Reply-To: <1303985279-3944-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

Keep the link key type together with connection and use it to
map security level to link key requirements. Authenticate and/or
encrypt connection if the link is insufficiently secure.

Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
---
 include/net/bluetooth/hci_core.h |    1 +
 net/bluetooth/hci_conn.c         |   61 +++++++++++++++++++++++++++++++------
 net/bluetooth/hci_event.c        |    4 ++
 3 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 69967e5..2da2eb9 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -226,6 +226,7 @@ struct hci_conn {
 	__u16		pkt_type;
 	__u16		link_policy;
 	__u32		link_mode;
+	__u8		key_type;
 	__u8		auth_type;
 	__u8		sec_level;
 	__u8		pending_sec_level;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 7a6f56b..74cd755 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -287,6 +287,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 	conn->auth_type = HCI_AT_GENERAL_BONDING;
 	conn->io_capability = hdev->io_capability;
 	conn->remote_auth = 0xff;
+	conn->key_type = 0xff;
 
 	conn->power_save = 1;
 	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
@@ -535,32 +536,72 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 	return 0;
 }
 
+/* Encrypt the the link */
+static void hci_conn_encrypt(struct hci_conn *conn)
+{
+	BT_DBG("conn %p", conn);
+
+	if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+		struct hci_cp_set_conn_encrypt cp;
+		cp.handle  = cpu_to_le16(conn->handle);
+		cp.encrypt = 0x01;
+		hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
+									&cp);
+	}
+}
+
 /* Enable security */
 int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 {
 	BT_DBG("conn %p", conn);
 
+	/* For sdp we don't need the link key. */
 	if (sec_level == BT_SECURITY_SDP)
 		return 1;
 
+	/* For non 2.1 devices and low security level we don't need the link
+	   key. */
 	if (sec_level == BT_SECURITY_LOW &&
 				(!conn->ssp_mode || !conn->hdev->ssp_mode))
 		return 1;
 
-	if (conn->link_mode & HCI_LM_ENCRYPT)
-		return hci_conn_auth(conn, sec_level, auth_type);
-
+	/* For other security levels we need the link key. */
+	if (!(conn->link_mode & HCI_LM_AUTH))
+		goto auth;
+
+	/* An authenticated combination key has sufficient security for any
+	   security level. */
+	if (conn->key_type == HCI_LK_AUTH_COMBINATION)
+		goto encrypt;
+
+	/* An unauthenticated combination key has sufficient security for
+	   security level 1 and 2. */
+	if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
+			(sec_level == BT_SECURITY_MEDIUM ||
+			sec_level == BT_SECURITY_LOW))
+		goto encrypt;
+
+	/* A combination key has always sufficient security for the security
+	   levels 1 or 2. High security level requires the combination key
+	   is generated using maximum PIN code length (16).
+	   For pre 2.1 units. */
+	if (conn->key_type == HCI_LK_COMBINATION &&
+			(sec_level != BT_SECURITY_HIGH ||
+			conn->pin_length == 16))
+		goto encrypt;
+
+auth:
 	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
 		return 0;
 
-	if (hci_conn_auth(conn, sec_level, auth_type)) {
-		struct hci_cp_set_conn_encrypt cp;
-		cp.handle  = cpu_to_le16(conn->handle);
-		cp.encrypt = 1;
-		hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
-							sizeof(cp), &cp);
-	}
+	hci_conn_auth(conn, sec_level, auth_type);
+	return 0;
+
+encrypt:
+	if (conn->link_mode & HCI_LM_ENCRYPT)
+		return 1;
 
+	hci_conn_encrypt(conn);
 	return 0;
 }
 EXPORT_SYMBOL(hci_conn_security);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 35f9898..655af8b 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2095,6 +2095,10 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
 		hci_conn_hold(conn);
 		conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 		pin_len = conn->pin_length;
+
+		if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
+			conn->key_type = ev->key_type;
+
 		hci_conn_put(conn);
 	}
 
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3 2/7] Bluetooth: Don't modify sec_level if auth failed
From: Waldemar Rymarkiewicz @ 2011-04-28 10:07 UTC (permalink / raw)
  To: Johan Hedberg, padovan; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
In-Reply-To: <1303985279-3944-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

If authentication fails the security level should stay as it was set
before the process has started. Setting BT_SECURITY_LOW can hide real
security level on a link eg. having BT_SECURITY_MEDIUM on the link,
re-authenticate with failure to get BT_SECURITY_HIGH, as  a result we
get BT_SECURITY_LOW on the link while the real security is still medium.

Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
---
 net/bluetooth/hci_event.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index fbbb63f..35f9898 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1459,7 +1459,6 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 			conn->sec_level = conn->pending_sec_level;
 		} else {
 			mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
-			conn->sec_level = BT_SECURITY_LOW;
 		}
 
 		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3 1/7] Bluetooth: Add definitions for link key types
From: Waldemar Rymarkiewicz @ 2011-04-28 10:07 UTC (permalink / raw)
  To: Johan Hedberg, padovan; +Cc: linux-bluetooth, Waldemar Rymarkiewicz
In-Reply-To: <1303985279-3944-1-git-send-email-waldemar.rymarkiewicz@tieto.com>

Introduce the link key types defs and use them instead of magic numbers.

Signed-off-by: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
---
 include/net/bluetooth/hci.h |    9 +++++++++
 net/bluetooth/hci_core.c    |    2 +-
 net/bluetooth/hci_event.c   |    7 ++++---
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 6138e31..e0a3cf1 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -246,6 +246,15 @@ enum {
 #define HCI_AT_GENERAL_BONDING		0x04
 #define HCI_AT_GENERAL_BONDING_MITM	0x05
 
+/* Link Key types */
+#define HCI_LK_COMBINATION		0x00
+#define HCI_LK_LOCAL_UNIT		0x01
+#define HCI_LK_REMOTE_UNIT		0x02
+#define HCI_LK_DEBUG_COMBINATION	0x03
+#define HCI_LK_UNAUTH_COMBINATION	0x04
+#define HCI_LK_AUTH_COMBINATION		0x05
+#define HCI_LK_CHANGED_COMBINATION	0x06
+
 /* -----  HCI Commands ---- */
 #define HCI_OP_NOP			0x0000
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 98aa24b..07d0ba3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1050,7 +1050,7 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
 	if (new_key)
 		mgmt_new_key(hdev->id, key, old_key_type);
 
-	if (type == 0x06)
+	if (type == HCI_LK_CHANGED_COMBINATION)
 		key->type = old_key_type;
 
 	return 0;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index e64a3de..fbbb63f 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2053,15 +2053,16 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
 	BT_DBG("%s found key type %u for %s", hdev->name, key->type,
 							batostr(&ev->bdaddr));
 
-	if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) {
+	if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) &&
+				key->type == HCI_LK_DEBUG_COMBINATION) {
 		BT_DBG("%s ignoring debug key", hdev->name);
 		goto not_found;
 	}
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
 
-	if (key->type == 0x04 && conn && conn->auth_type != 0xff &&
-						(conn->auth_type & 0x01)) {
+	if (key->type == HCI_LK_UNAUTH_COMBINATION && conn &&
+			conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
 		BT_DBG("%s ignoring unauthenticated key", hdev->name);
 		goto not_found;
 	}
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3 0/7] Handle link key type and security requirements
From: Waldemar Rymarkiewicz @ 2011-04-28 10:07 UTC (permalink / raw)
  To: Johan Hedberg, padovan; +Cc: linux-bluetooth, Waldemar Rymarkiewicz

Johan, 

I modified patch 6/7 according to your comment and have added a new patch 7/7 which is an
extension of mgmt api to require secure pin code.

Thanks,
Waldek

Waldemar Rymarkiewicz (7):
  Bluetooth: Add definitions for link key types
  Bluetooth: Don't modify sec_level if auth failed
  Bluetooth: Map sec_level to link key requirements
  Bluetooth: Ignore key unauthenticated for high security
  Bluetooth: Double check sec req for pre 2.1 device
  Bluetooth: Respect local MITM req in io_cap reply
  Bluetooth: Add secure flag for mgmt_pin_code_req

 include/net/bluetooth/hci.h      |    9 +++++
 include/net/bluetooth/hci_core.h |    3 +-
 include/net/bluetooth/mgmt.h     |    1 +
 net/bluetooth/hci_conn.c         |   61 +++++++++++++++++++++++++++++++------
 net/bluetooth/hci_core.c         |    2 +-
 net/bluetooth/hci_event.c        |   39 ++++++++++++++++++-----
 net/bluetooth/mgmt.c             |    3 +-
 net/bluetooth/rfcomm/core.c      |   17 ++++++++++-
 8 files changed, 112 insertions(+), 23 deletions(-)


^ permalink raw reply

* Re: [PATCH] bluetooth: Fix for security block issue.
From: Ville Tervo @ 2011-04-28  9:51 UTC (permalink / raw)
  To: Antti Julku
  Cc: ext Marcel Holtmann, linux-bluetooth, Lukasz Rymanowski,
	linus.walleij, par-gunnar.p.hjalmdahl, padovan
In-Reply-To: <4DB935D9.5080302@nokia.com>

Hi,

On Thu, Apr 28, 2011 at 12:39:37PM +0300, Antti Julku wrote:
> 
> Hi,
> 
> On 01/25/2011 06:13 PM, ext Marcel Holtmann wrote:
> >Hi Lukasz,
> >
> >>It can happen that controller will schedule ACL data
> >>containing L2CAP connect request to host just before
> >>encryption change event, even though link is encrypted on
> >>LMP level before L2CAP connect request come.
> >>With this fix, L2CAP layer will handle such scenario.
> >
> >I really don't like to have a work around for this. It is clearly a bug
> >in the controller.
> 
> We see this security block issue all the time in our automated
> testing at Nokia. RFCOMM connections to an Ubuntu PC fail randomly
> because of security block, for example when sending files over OPP.
> 
> Hcidump always shows L2CAP before Encrypt Change:
> > ACL data: handle 42 flags 0x02 dlen 12
>     L2CAP(s): Connect req: psm 3 scid 0x0041
> < ACL data: handle 42 flags 0x02 dlen 16
>     L2CAP(s): Connect rsp: dcid 0x0000 scid 0x0041 result 3 status 0
>       Connection refused - security block
> > HCI Event: Encrypt Change (0x08) plen 4
>     status 0x00 handle 42 encrypt 0x01
> 
> It's easy to reproduce at least with these dongles:
> 
> Alink BLUEUSB21 (BCM)
> Belkin BT2.1 F8T017 (BCM)
> DeLock 2.1 (CSR)
> PTS 2.1 (CSR)
> 
> So most of our BT 2.1 dongles seem to be buggy. It would be nice to
> have a workaround since it happens with so many dongles.

Could the actual reason be some change in usb stack? Could it have lower
priority for event pipe than for data pipe? In that case event for security
change might arrive to bt stack too late.

At lest I haven't seen this kind of behaviour with serial attached chips. So I
think this is something USB specific.

-- 
Ville

^ permalink raw reply

* Re: [PATCH] bluetooth: Fix for security block issue.
From: Antti Julku @ 2011-04-28  9:39 UTC (permalink / raw)
  To: ext Marcel Holtmann, linux-bluetooth
  Cc: Lukasz Rymanowski, linus.walleij, par-gunnar.p.hjalmdahl, padovan,
	ville.tervo
In-Reply-To: <1295971990.1520.53.camel@aeonflux>


Hi,

On 01/25/2011 06:13 PM, ext Marcel Holtmann wrote:
> Hi Lukasz,
>
>> It can happen that controller will schedule ACL data
>> containing L2CAP connect request to host just before
>> encryption change event, even though link is encrypted on
>> LMP level before L2CAP connect request come.
>> With this fix, L2CAP layer will handle such scenario.
>
> I really don't like to have a work around for this. It is clearly a bug
> in the controller.

We see this security block issue all the time in our automated testing 
at Nokia. RFCOMM connections to an Ubuntu PC fail randomly because of 
security block, for example when sending files over OPP.

Hcidump always shows L2CAP before Encrypt Change:
 > ACL data: handle 42 flags 0x02 dlen 12
     L2CAP(s): Connect req: psm 3 scid 0x0041
< ACL data: handle 42 flags 0x02 dlen 16
     L2CAP(s): Connect rsp: dcid 0x0000 scid 0x0041 result 3 status 0
       Connection refused - security block
 > HCI Event: Encrypt Change (0x08) plen 4
     status 0x00 handle 42 encrypt 0x01

It's easy to reproduce at least with these dongles:

Alink BLUEUSB21 (BCM)
Belkin BT2.1 F8T017 (BCM)
DeLock 2.1 (CSR)
PTS 2.1 (CSR)

So most of our BT 2.1 dongles seem to be buggy. It would be nice to have 
a workaround since it happens with so many dongles.

Br,
Antti

^ permalink raw reply

* [Patch] Update hid2hci tool from udev codebase
From: Kay Sievers @ 2011-04-28  9:08 UTC (permalink / raw)
  To: linux-bluetooth

commit 4a2b9643b6e81d12c3c5fb863d1cca353437e102
Author: Kay Sievers <kay.sievers@vrfy.org>
Date:   Thu Apr 28 11:02:24 2011 +0200

    Update hid2hci tool from udev codebase

diff --git a/Makefile.tools b/Makefile.tools
index 364db37..1bf21b2 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -102,7 +102,7 @@ endif
 if HID2HCI
 sbin_PROGRAMS += tools/hid2hci
 
-tools_hid2hci_LDADD = @USB_LIBS@
+tools_hid2hci_LDADD = @USB_LIBS@ @UDEV_LIBS@
 
 dist_man_MANS += tools/hid2hci.8
 else
diff --git a/acinclude.m4 b/acinclude.m4
index 22fcd5c..a27cd22 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -148,6 +148,12 @@ AC_DEFUN([AC_PATH_USB], [
 			[Define to 1 if you need the usb_interrupt_read() function.]))
 ])
 
+AC_DEFUN([AC_PATH_UDEV], [
+	PKG_CHECK_MODULES(UDEV, libudev, udev_found=yes, udev_found=no)
+	AC_SUBST(UDEV_CFLAGS)
+	AC_SUBST(UDEV_LIBS)
+])
+
 AC_DEFUN([AC_PATH_SNDFILE], [
 	PKG_CHECK_MODULES(SNDFILE, sndfile, sndfile_found=yes, sndfile_found=no)
 	AC_SUBST(SNDFILE_CFLAGS)
diff --git a/configure.ac b/configure.ac
index 4447f79..cf32e01 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,6 +40,7 @@ AC_PATH_GLIB
 AC_PATH_ALSA
 AC_PATH_GSTREAMER
 AC_PATH_USB
+AC_PATH_UDEV
 AC_PATH_SNDFILE
 AC_PATH_OUI
 AC_PATH_READLINE
diff --git a/scripts/bluetooth-hid2hci.rules b/scripts/bluetooth-hid2hci.rules
index 1b231d1..3b36629 100644
--- a/scripts/bluetooth-hid2hci.rules
+++ b/scripts/bluetooth-hid2hci.rules
@@ -1,36 +1,30 @@
-# Variety of Dell Bluetooth devices
-#
-# it looks like a bit of an odd rule, because it is matching
-# on a mouse device that is self powered, but that is where
-# a HID report needs to be sent to switch modes.
-#
-# Known supported devices:
-#   413c:8154
-#   413c:8158
-#   413c:8162
-ACTION=="add", ENV{ID_VENDOR}=="413c", ENV{ID_CLASS}=="mouse", ATTRS{bmAttributes}=="e0", KERNEL=="mouse*", RUN+="/usr/sbin/hid2hci --method dell -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
+# do not edit this file, it will be overwritten on update
+
+ACTION=="remove", GOTO="hid2hci_end"
+SUBSYSTEM!="usb", GOTO="hid2hci_end"
+
+# Variety of Dell Bluetooth devices - match on a mouse device that is
+# self powered and where a HID report needs to be sent to switch modes
+# Known supported devices: 413c:8154, 413c:8158, 413c:8162
+ATTR{bInterfaceClass}=="03", ATTR{bInterfaceSubClass}=="01", ATTR{bInterfaceProtocol}=="02", \
+  ATTRS{bDeviceClass}=="00", ATTRS{idVendor}=="413c", ATTRS{bmAttributes}=="e0", \
+  RUN+="hid2hci --method=dell --devpath=%p", ENV{HID2HCI_SWITCH}="1"
 
 # Logitech devices
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c703" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c704" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c705" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70a" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70b" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70c" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70e" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c713" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c714" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c71b" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c71c" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
+KERNEL=="hiddev*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c70[35e]", \
+  RUN+="hid2hci --method=logitech-hid --devpath=%p"
+KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c70[4abc]|c71[34bc]", \
+  RUN+="hid2hci --method=logitech-hid --devpath=%p"
+
+ENV{DEVTYPE}!="usb_device", GOTO="hid2hci_end"
+
+# When a Dell device recovers from S3, the mouse child needs to be repoked
+# Unfortunately the only event seen is the BT device disappearing, so the mouse
+# device needs to be chased down on the USB bus.
+ATTR{bDeviceClass}=="e0", ATTR{bDeviceSubClass}=="01", ATTR{bDeviceProtocol}=="01", ATTR{idVendor}=="413c", \
+  ENV{REMOVE_CMD}="/sbin/udevadm trigger --action=change --subsystem-match=usb --property-match=HID2HCI_SWITCH=1"
 
-# CSR devices (in HID mode)
-ACTION=="add", ENV{ID_VENDOR}=="0a12", ENV{ID_MODEL}=="1000" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="0458", ENV{ID_MODEL}=="1000" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="1000" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
+# CSR devices
+ATTR{idVendor}=="0a12|0458|05ac", ATTR{idProduct}=="1000", RUN+="hid2hci --method=csr --devpath=%p"
 
-# CSR devices (in HCI mode)
-#ACTION=="add", ENV{ID_VENDOR}=="0a12", ENV{ID_MODEL}=="0001" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="0458", ENV{ID_MODEL}=="003f" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="8203" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="8204" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="8207" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
+LABEL="hid2hci_end"
diff --git a/tools/hid2hci.8 b/tools/hid2hci.8
index 5d35274..6ea7ed8 100644
--- a/tools/hid2hci.8
+++ b/tools/hid2hci.8
@@ -29,23 +29,18 @@ is used to set up switch supported Bluetooth devices into the HCI
 mode and back.
 .SH OPTIONS
 .TP
-.BI -h
-Gives a list of possible options.
-.TP
-.BI -q
-Don't display any messages.
-.TP
-.BI -r [hid,hci]
+.B --mode= [hid, hci]
 Sets the mode to switch the device into
 .TP
-.BI -v
-Specifies the 4 digit vendor ID assigned to the device being switched
+.B --method= [csr, logitech-hid, dell]
+Which vendor method to use for switching the device.
 .TP
-.BI -p
-Specifies the 4 digit product ID assigned to the device being switched
+.B --devpath=
+Specifies the device path in /sys
+.TP
+.B --help
+Gives a list of possible options.
 .TP
-.BI -m [csr, logitech, dell]
-Which vendor method to use for switching the device.
 .SH AUTHOR
 Written by Marcel Holtmann <marcel@holtmann.org>.
 .br
diff --git a/tools/hid2hci.c b/tools/hid2hci.c
index a640772..dea3974 100644
--- a/tools/hid2hci.c
+++ b/tools/hid2hci.c
@@ -1,9 +1,10 @@
 /*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
+ * hid2hci : switch the radio on devices that support
+ *           it from HID to HCI and back
  *
  *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
- *
+ *  Copyright (C) 2008-2009  Mario Limonciello <mario_limonciello@dell.com>
+ *  Copyright (C) 2009-2011  Kay Sievers <kay.sievers@vrfy.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -32,79 +33,24 @@
 #include <string.h>
 #include <getopt.h>
 #include <sys/ioctl.h>
-
+#include <linux/types.h>
+#include <linux/hiddev.h>
 #include <usb.h>
 
-#ifdef NEED_USB_GET_BUSSES
-static inline struct usb_bus *usb_get_busses(void)
-{
-	return usb_busses;
-}
-#endif
-
-#ifndef USB_DIR_OUT
-#define USB_DIR_OUT	0x00
-#endif
-
-static char devpath[PATH_MAX + 1] = "/dev";
-
-struct hiddev_devinfo {
-	unsigned int bustype;
-	unsigned int busnum;
-	unsigned int devnum;
-	unsigned int ifnum;
-	short vendor;
-	short product;
-	short version;
-	unsigned num_applications;
-};
+#include "libudev.h"
 
-struct hiddev_report_info {
-	unsigned report_type;
-	unsigned report_id;
-	unsigned num_fields;
+enum mode {
+	HCI = 0,
+	HID = 1,
 };
 
-typedef __signed__ int __s32;
-
-struct hiddev_usage_ref {
-	unsigned report_type;
-	unsigned report_id;
-	unsigned field_index;
-	unsigned usage_index;
-	unsigned usage_code;
-	__s32 value;
-};
-
-#define HIDIOCGDEVINFO		_IOR('H', 0x03, struct hiddev_devinfo)
-#define HIDIOCINITREPORT	_IO('H', 0x05)
-#define HIDIOCSREPORT		_IOW('H', 0x08, struct hiddev_report_info)
-#define HIDIOCSUSAGE		_IOW('H', 0x0C, struct hiddev_usage_ref)
-
-#define HID_REPORT_TYPE_OUTPUT	2
-
-#define HCI 0
-#define HID 1
-
-struct device_info {
-	struct usb_device *dev;
-	int mode;
-	uint16_t vendor;
-	uint16_t product;
-};
-
-static int switch_csr(struct device_info *devinfo)
+static int usb_switch_csr(struct usb_dev_handle *dev, enum mode mode)
 {
-	struct usb_dev_handle *udev;
 	int err;
 
-	udev = usb_open(devinfo->dev);
-	if (!udev)
-		return -errno;
-
-	err = usb_control_msg(udev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-				0, devinfo->mode, 0, NULL, 0, 10000);
-
+	err = usb_control_msg(dev,
+			      USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      0, mode, 0, NULL, 0, 10000);
 	if (err == 0) {
 		err = -1;
 		errno = EALREADY;
@@ -112,13 +58,10 @@ static int switch_csr(struct device_info *devinfo)
 		if (errno == ETIMEDOUT)
 			err = 0;
 	}
-
-	usb_close(udev);
-
 	return err;
 }
 
-static int send_report(int fd, const char *buf, size_t size)
+static int hid_logitech_send_report(int fd, const char *buf, size_t size)
 {
 	struct hiddev_report_info rinfo;
 	struct hiddev_usage_ref uref;
@@ -147,72 +90,42 @@ static int send_report(int fd, const char *buf, size_t size)
 	return err;
 }
 
-static int switch_logitech(struct device_info *devinfo)
+static int hid_switch_logitech(const char *filename)
 {
-	char devname[PATH_MAX + 1];
-	int i, fd, err = -1;
-
-	for (i = 0; i < 16; i++) {
-		struct hiddev_devinfo dinfo;
-		char rep1[] = { 0xff, 0x80, 0x80, 0x01, 0x00, 0x00 };
-		char rep2[] = { 0xff, 0x80, 0x00, 0x00, 0x30, 0x00 };
-		char rep3[] = { 0xff, 0x81, 0x80, 0x00, 0x00, 0x00 };
-
-		sprintf(devname, "%s/hiddev%d", devpath, i);
-		fd = open(devname, O_RDWR);
-		if (fd < 0) {
-			sprintf(devname, "%s/usb/hiddev%d", devpath, i);
-			fd = open(devname, O_RDWR);
-			if (fd < 0) {
-				sprintf(devname, "%s/usb/hid/hiddev%d", devpath, i);
-				fd = open(devname, O_RDWR);
-				if (fd < 0)
-					continue;
-			}
-		}
-
-		memset(&dinfo, 0, sizeof(dinfo));
-		err = ioctl(fd, HIDIOCGDEVINFO, &dinfo);
-		if (err < 0 || (int) dinfo.busnum != atoi(devinfo->dev->bus->dirname) ||
-				(int) dinfo.devnum != atoi(devinfo->dev->filename)) {
-			close(fd);
-			continue;
-		}
-
-		err = ioctl(fd, HIDIOCINITREPORT, 0);
-		if (err < 0) {
-			close(fd);
-			break;
-		}
-
-		err = send_report(fd, rep1, sizeof(rep1));
-		if (err < 0) {
-			close(fd);
-			break;
-		}
-
-		err = send_report(fd, rep2, sizeof(rep2));
-		if (err < 0) {
-			close(fd);
-			break;
-		}
-
-		err = send_report(fd, rep3, sizeof(rep3));
-		close(fd);
-		break;
-	}
-
+	char rep1[] = { 0xff, 0x80, 0x80, 0x01, 0x00, 0x00 };
+	char rep2[] = { 0xff, 0x80, 0x00, 0x00, 0x30, 0x00 };
+	char rep3[] = { 0xff, 0x81, 0x80, 0x00, 0x00, 0x00 };
+	int fd;
+	int err = -1;
+
+	fd = open(filename, O_RDWR);
+	if (fd < 0)
+		return err;
+
+	err = ioctl(fd, HIDIOCINITREPORT, 0);
+	if (err < 0)
+		goto out;
+
+	err = hid_logitech_send_report(fd, rep1, sizeof(rep1));
+	if (err < 0)
+		goto out;
+
+	err = hid_logitech_send_report(fd, rep2, sizeof(rep2));
+	if (err < 0)
+		goto out;
+
+	err = hid_logitech_send_report(fd, rep3, sizeof(rep3));
+out:
+	close(fd);
 	return err;
 }
 
-static int switch_dell(struct device_info *devinfo)
+static int usb_switch_dell(struct usb_dev_handle *dev, enum mode mode)
 {
 	char report[] = { 0x7f, 0x00, 0x00, 0x00 };
-
-	struct usb_dev_handle *handle;
 	int err;
 
-	switch (devinfo->mode) {
+	switch (mode) {
 	case HCI:
 		report[1] = 0x13;
 		break;
@@ -221,22 +134,16 @@ static int switch_dell(struct device_info *devinfo)
 		break;
 	}
 
-	handle = usb_open(devinfo->dev);
-	if (!handle)
-		return -EIO;
-
 	/* Don't need to check return, as might not be in use */
-	usb_detach_kernel_driver_np(handle, 0);
+	usb_detach_kernel_driver_np(dev, 0);
 
-	if (usb_claim_interface(handle, 0) < 0) {
-		usb_close(handle);
+	if (usb_claim_interface(dev, 0) < 0)
 		return -EIO;
-	}
 
-	err = usb_control_msg(handle,
-		USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+	err = usb_control_msg(dev,
+			USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 			USB_REQ_SET_CONFIGURATION, 0x7f | (0x03 << 8), 0,
-						report, sizeof(report), 5000);
+			report, sizeof(report), 5000);
 
 	if (err == 0) {
 		err = -1;
@@ -245,131 +152,200 @@ static int switch_dell(struct device_info *devinfo)
 		if (errno == ETIMEDOUT)
 			err = 0;
 	}
-
-	usb_close(handle);
-
 	return err;
 }
 
-static int find_device(struct device_info* devinfo)
+/*
+ * libusb needs to scan and open all devices, just to to find the
+ * device we already have. This should be fixed in libusb.
+ */
+static struct usb_device *usb_device_open_from_udev(struct udev_device *usb_dev)
 {
 	struct usb_bus *bus;
-	struct usb_device *dev;
+	const char *str;
+	int busnum;
+	int devnum;
+
+	str = udev_device_get_sysattr_value(usb_dev, "busnum");
+	if (str == NULL)
+		return NULL;
+	busnum = strtol(str, NULL, 0);
 
+	str = udev_device_get_sysattr_value(usb_dev, "devnum");
+	if (str == NULL)
+		return NULL;
+	devnum = strtol(str, NULL, 0);
+
+	usb_init();
 	usb_find_busses();
 	usb_find_devices();
 
-	for (bus = usb_get_busses(); bus; bus = bus->next)
+	for (bus = usb_get_busses(); bus; bus = bus->next) {
+		struct usb_device *dev;
+
+		if (strtol(bus->dirname, NULL, 10) != busnum)
+			continue;
+
 		for (dev = bus->devices; dev; dev = dev->next) {
-			if (dev->descriptor.idVendor == devinfo->vendor &&
-			    dev->descriptor.idProduct == devinfo->product) {
-				devinfo->dev=dev;
-				return 1;
-			}
+			if (dev->devnum == devnum)
+				return dev;
 		}
-	return 0;
+	}
+
+	return NULL;
 }
 
-static void usage(char* error)
+static struct usb_dev_handle *find_device(struct udev_device *udev_dev)
+{
+	struct usb_device *dev;
+
+	dev = usb_device_open_from_udev(udev_dev);
+	if (dev == NULL)
+		return NULL;
+	return usb_open(dev);
+}
+
+static void usage(const char *error)
 {
 	if (error)
 		fprintf(stderr,"\n%s\n", error);
 	else
 		printf("hid2hci - Bluetooth HID to HCI mode switching utility\n\n");
 
-	printf("Usage:\n"
-		"\thid2hci [options]\n"
-		"\n");
-
-	printf("Options:\n"
-		"\t-h, --help           Display help\n"
-		"\t-q, --quiet          Don't display any messages\n"
-		"\t-r, --mode=          Mode to switch to [hid, hci]\n"
-		"\t-v, --vendor=        Vendor ID to act upon\n"
-		"\t-p, --product=       Product ID to act upon\n"
-		"\t-m, --method=        Method to use to switch [csr, logitech, dell]\n"
-		"\n");
-	if (error)
-		exit(1);
+	printf("Usage: hid2hci [options]\n"
+		"  --mode=               mode to switch to [hid|hci] (default hci)\n"
+		"  --devpath=            sys device path\n"
+		"  --method=             method to use to switch [csr|logitech-hid|dell]\n"
+		"  --help\n\n");
 }
 
-static struct option main_options[] = {
-	{ "help",	no_argument, 0, 'h' },
-	{ "quiet",	no_argument, 0, 'q' },
-	{ "mode",	required_argument, 0, 'r' },
-	{ "vendor",	required_argument, 0, 'v' },
-	{ "product",	required_argument, 0, 'p' },
-	{ "method",	required_argument, 0, 'm' },
-	{ 0, 0, 0, 0 }
-};
-
 int main(int argc, char *argv[])
 {
-	struct device_info dev = { NULL, HCI, 0, 0 };
-	int opt, quiet = 0;
-	int (*method)(struct device_info *dev) = NULL;
-
-	while ((opt = getopt_long(argc, argv, "+r:v:p:m:qh", main_options, NULL)) != -1) {
-		switch (opt) {
-		case 'r':
-			if (optarg && !strcmp(optarg, "hid"))
-				dev.mode = HID;
-			else if (optarg && !strcmp(optarg, "hci"))
-				dev.mode = HCI;
-			else
-				usage("ERROR: Undefined radio mode\n");
+	static const struct option options[] = {
+		{ "help", no_argument, NULL, 'h' },
+		{ "mode", required_argument, NULL, 'm' },
+		{ "devpath", required_argument, NULL, 'p' },
+		{ "method", required_argument, NULL, 'M' },
+		{ }
+	};
+	enum method {
+		METHOD_UNDEF,
+		METHOD_CSR,
+		METHOD_LOGITECH_HID,
+		METHOD_DELL,
+	} method = METHOD_UNDEF;
+	struct udev *udev;
+	struct udev_device *udev_dev = NULL;
+	char syspath[PATH_MAX];
+	int (*usb_switch)(struct usb_dev_handle *dev, enum mode mode) = NULL;
+	enum mode mode = HCI;
+	const char *devpath = NULL;
+	int err = -1;
+	int rc = 1;
+
+	for (;;) {
+		int option;
+
+		option = getopt_long(argc, argv, "m:p:M:h", options, NULL);
+		if (option == -1)
 			break;
-		case 'v':
-			sscanf(optarg, "%4hx", &dev.vendor);
+
+		switch (option) {
+		case 'm':
+			if (!strcmp(optarg, "hid")) {
+				mode = HID;
+			} else if (!strcmp(optarg, "hci")) {
+				mode = HCI;
+			} else {
+				usage("error: undefined radio mode\n");
+				exit(1);
+			}
 			break;
 		case 'p':
-			sscanf(optarg, "%4hx", &dev.product);
+			devpath = optarg;
 			break;
-		case 'm':
-			if (optarg && !strcmp(optarg, "csr"))
-				method = switch_csr;
-			else if (optarg && !strcmp(optarg, "logitech"))
-				method = switch_logitech;
-			else if (optarg && !strcmp(optarg, "dell"))
-				method = switch_dell;
-			else
-				usage("ERROR: Undefined switching method\n");
-			break;
-		case 'q':
-			quiet = 1;
+		case 'M':
+			if (!strcmp(optarg, "csr")) {
+				method = METHOD_CSR;
+				usb_switch = usb_switch_csr;
+			} else if (!strcmp(optarg, "logitech-hid")) {
+				method = METHOD_LOGITECH_HID;
+			} else if (!strcmp(optarg, "dell")) {
+				method = METHOD_DELL;
+				usb_switch = usb_switch_dell;
+			} else {
+				usage("error: undefined switching method\n");
+				exit(1);
+			}
 			break;
 		case 'h':
 			usage(NULL);
-		default:
-			exit(0);
 		}
 	}
 
-	if (!quiet && (!dev.vendor || !dev.product || !method))
-		usage("ERROR: Vendor ID, Product ID, and Switching Method must all be defined.\n");
+	if (!devpath || method == METHOD_UNDEF) {
+		usage("error: --devpath= and --method= must be defined\n");
+		exit(1);
+	}
 
-	argc -= optind;
-	argv += optind;
-	optind = 0;
+	udev = udev_new();
+	if (udev == NULL)
+		goto exit;
 
-	usb_init();
-
-	if (!find_device(&dev)) {
-		if (!quiet)
-			fprintf(stderr, "Device %04x:%04x not found on USB bus.\n",
-				dev.vendor, dev.product);
-		exit(1);
+	snprintf(syspath, sizeof(syspath), "%s/%s", udev_get_sys_path(udev), devpath);
+	udev_dev = udev_device_new_from_syspath(udev, syspath);
+	if (udev_dev == NULL) {
+		fprintf(stderr, "error: could not find '%s'\n", devpath);
+		goto exit;
 	}
 
-	if (!quiet)
-		printf("Attempting to switch device %04x:%04x to %s mode ",
-			dev.vendor, dev.product, dev.mode ? "HID" : "HCI");
-	fflush(stdout);
+	switch (method) {
+	case METHOD_CSR:
+	case METHOD_DELL: {
+		struct udev_device *dev;
+		struct usb_dev_handle *handle;
+		const char *type;
+
+		/* get the parent usb_device if needed */
+		dev = udev_dev;
+		type = udev_device_get_devtype(dev);
+		if (type == NULL || strcmp(type, "usb_device") != 0) {
+			dev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");
+			if (dev == NULL) {
+				fprintf(stderr, "error: could not find usb_device for '%s'\n", devpath);
+				goto exit;
+			}
+		}
+
+		handle = find_device(dev);
+		if (handle == NULL) {
+			fprintf(stderr, "error: unable to handle '%s'\n",
+				udev_device_get_syspath(dev));
+			goto exit;
+		}
+		err = usb_switch(handle, mode);
+		break;
+	}
+	case METHOD_LOGITECH_HID: {
+		const char *device;
 
-	if (method(&dev) < 0 && !quiet)
-		printf("failed (%s)\n", strerror(errno));
-	else if (!quiet)
-		printf("was successful\n");
+		device = udev_device_get_devnode(udev_dev);
+		if (device == NULL) {
+			fprintf(stderr, "error: could not find hiddev device node\n");
+			goto exit;
+		}
+		err = hid_switch_logitech(device);
+		break;
+	}
+	default:
+		break;
+	}
 
-	return errno;
+	if (err < 0)
+		fprintf(stderr, "error: switching device '%s' failed.\n",
+			udev_device_get_syspath(udev_dev));
+exit:
+	udev_device_unref(udev_dev);
+	udev_unref(udev);
+	return rc;
 }



^ permalink raw reply related

* Google Summer of Code 2011 projects
From: Gustavo F. Padovan @ 2011-04-28  6:06 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org

Hi everyone,

We got four slots in this year's Google Summer of Code. The students and
projects are listed here(The same info is also in Google melange[0])

Improve EDS backend of Phone Book Access Profile (PBAP)
Student: Bartosz Szatkowski
Mentor: Claudio Takahasi

Nintendo Wii Remote Device Driver
Student: David Herrmann
Mentor: Gustavo Padovan

Implementing the Basic Imaging Profile(BIP)
Student: Jakub Adamek
Mentor: Vinicius Gomes

Implement the Video Distribution Profile(VDP)
Student: Prasad Bhat
Mentor: Luiz Augusto von Dentz

The students should soon introduce theirselves and their projects to the
community, stay tuned. And happy hacking to all students. :)

Regards,


[0] http://www.google-melange.com/gsoc/org/google/gsoc2011/bluez

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: kernel panic after unplug usb bluetooth dongle
From: Dave Young @ 2011-04-28  5:30 UTC (permalink / raw)
  To: Dave Young, Bluettooth Linux, Linux Kernel Mailing List,
	Thomas Gleixner
In-Reply-To: <20110427175432.GA2328@joana>

On Thu, Apr 28, 2011 at 1:54 AM, Gustavo F. Padovan
<padovan@profusion.mobi> wrote:
> * Dave Young <hidave.darkstar@gmail.com> [2011-04-27 14:35:59 +0800]:
>
>> Hi,
>>
>> Unplug usb bluetooth dongle make kernel panic as below. Thomas, any
>> idea about it?
>
> Commit b79f44c16a4 on
>
>        git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-2.6.git
>
> fixes this. The only problem is that it didn't arrive at mainline yet.

Confirmed, thank you.

>
> --
> Gustavo F. Padovan
> http://profusion.mobi
>



-- 
Regards
dave

^ permalink raw reply

* [PATCH -v2 3/3] Bluetooth: Remove l2cap_sk_list
From: Gustavo F. Padovan @ 2011-04-28  5:27 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1303968420-12719-2-git-send-email-padovan@profusion.mobi>

A new list was added to replace the socket based one. This new list
doesn't depent on sock and then fits better inside l2cap_core.c code.

It also rename l2cap_chan_alloc() to l2cap_chan_create() and
l2cap_chan_free() to l2cap_chan_destroy)

Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
 include/net/bluetooth/l2cap.h |    6 +-
 net/bluetooth/l2cap_core.c    |  165 ++++++++++++++++++++++-------------------
 net/bluetooth/l2cap_sock.c    |    6 +-
 3 files changed, 95 insertions(+), 82 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index fb3f90e..d09c9b1 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -350,6 +350,7 @@ struct l2cap_chan {
 	struct list_head	srej_l;
 
 	struct list_head list;
+	struct list_head global_l;
 };
 
 struct l2cap_conn {
@@ -441,7 +442,6 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
 #define __is_sar_start(ctrl)	(((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
 
 extern int disable_ertm;
-extern struct bt_sock_list l2cap_sk_list;
 
 int l2cap_init_sockets(void);
 void l2cap_cleanup_sockets(void);
@@ -469,9 +469,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent);
 struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
 							int proto, gfp_t prio);
 void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err);
-struct l2cap_chan *l2cap_chan_alloc(struct sock *sk);
+struct l2cap_chan *l2cap_chan_create(struct sock *sk);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
-void l2cap_chan_free(struct l2cap_chan *chan);
+void l2cap_chan_destroy(struct l2cap_chan *chan);
 int l2cap_chan_connect(struct l2cap_chan *chan);
 
 #endif /* __L2CAP_H */
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9e3f64f..d0769a8 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -62,9 +62,8 @@ static u8 l2cap_fixed_chan[8] = { 0x02, };
 
 static struct workqueue_struct *_busy_wq;
 
-struct bt_sock_list l2cap_sk_list = {
-	.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
-};
+LIST_HEAD(chan_list);
+DEFINE_RWLOCK(chan_list_lock);
 
 static void l2cap_busy_work(struct work_struct *work);
 
@@ -135,29 +134,27 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn
 	return c;
 }
 
-static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
+static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
 {
-	struct sock *sk;
-	struct hlist_node *node;
-	sk_for_each(sk, node, &l2cap_sk_list.head) {
-		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+	struct l2cap_chan *c;
 
-		if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src))
+	list_for_each_entry(c, &chan_list, global_l) {
+		if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
 			goto found;
 	}
 
-	sk = NULL;
+	c = NULL;
 found:
-	return sk;
+	return c;
 }
 
 int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
 {
 	int err;
 
-	write_lock_bh(&l2cap_sk_list.lock);
+	write_lock_bh(&chan_list_lock);
 
-	if (psm && __l2cap_get_sock_by_addr(psm, src)) {
+	if (psm && __l2cap_global_chan_by_addr(psm, src)) {
 		err = -EADDRINUSE;
 		goto done;
 	}
@@ -171,7 +168,7 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
 
 		err = -EINVAL;
 		for (p = 0x1001; p < 0x1100; p += 2)
-			if (!__l2cap_get_sock_by_addr(cpu_to_le16(p), src)) {
+			if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
 				chan->psm   = cpu_to_le16(p);
 				chan->sport = cpu_to_le16(p);
 				err = 0;
@@ -180,17 +177,17 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
 	}
 
 done:
-	write_unlock_bh(&l2cap_sk_list.lock);
+	write_unlock_bh(&chan_list_lock);
 	return err;
 }
 
 int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid)
 {
-	write_lock_bh(&l2cap_sk_list.lock);
+	write_lock_bh(&chan_list_lock);
 
 	chan->scid = scid;
 
-	write_unlock_bh(&l2cap_sk_list.lock);
+	write_unlock_bh(&chan_list_lock);
 
 	return 0;
 }
@@ -207,7 +204,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 	return 0;
 }
 
-struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
+struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 {
 	struct l2cap_chan *chan;
 
@@ -217,11 +214,19 @@ struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
 
 	chan->sk = sk;
 
+	write_lock_bh(&chan_list_lock);
+	list_add(&chan->global_l, &chan_list);
+	write_unlock_bh(&chan_list_lock);
+
 	return chan;
 }
 
-void l2cap_chan_free(struct l2cap_chan *chan)
+void l2cap_chan_destroy(struct l2cap_chan *chan)
 {
+	write_lock_bh(&chan_list_lock);
+	list_del(&chan->global_l);
+	write_unlock_bh(&chan_list_lock);
+
 	kfree(chan);
 }
 
@@ -651,48 +656,51 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 /* Find socket with cid and source bdaddr.
  * Returns closest match, locked.
  */
-static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
+static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
 {
-	struct sock *sk = NULL, *sk1 = NULL;
-	struct hlist_node *node;
+	struct l2cap_chan *c, *c1 = NULL;
 
-	read_lock(&l2cap_sk_list.lock);
+	read_lock(&chan_list_lock);
 
-	sk_for_each(sk, node, &l2cap_sk_list.head) {
-		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+	list_for_each_entry(c, &chan_list, global_l) {
+		struct sock *sk = c->sk;
 
 		if (state && sk->sk_state != state)
 			continue;
 
-		if (chan->scid == cid) {
+		if (c->scid == cid) {
 			/* Exact match. */
-			if (!bacmp(&bt_sk(sk)->src, src))
-				break;
+			if (!bacmp(&bt_sk(sk)->src, src)) {
+				read_unlock(&chan_list_lock);
+				return c;
+			}
 
 			/* Closest match */
 			if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
-				sk1 = sk;
+				c1 = c;
 		}
 	}
 
-	read_unlock(&l2cap_sk_list.lock);
+	read_unlock(&chan_list_lock);
 
-	return node ? sk : sk1;
+	return c1;
 }
 
 static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 {
 	struct sock *parent, *sk;
-	struct l2cap_chan *chan;
+	struct l2cap_chan *chan, *pchan;
 
 	BT_DBG("");
 
 	/* Check if we have socket listening on cid */
-	parent = l2cap_get_sock_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
+	pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
 							conn->src);
-	if (!parent)
+	if (!pchan)
 		return;
 
+	parent = pchan->sk;
+
 	bh_lock_sock(parent);
 
 	/* Check for backlog size */
@@ -705,7 +713,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 	if (!sk)
 		goto clean;
 
-	chan = l2cap_chan_alloc(sk);
+	chan = l2cap_chan_create(sk);
 	if (!chan) {
 		l2cap_sock_kill(sk);
 		goto clean;
@@ -883,33 +891,34 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *ch
 /* Find socket with psm and source bdaddr.
  * Returns closest match.
  */
-static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
+static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
 {
-	struct sock *sk = NULL, *sk1 = NULL;
-	struct hlist_node *node;
+	struct l2cap_chan *c, *c1 = NULL;
 
-	read_lock(&l2cap_sk_list.lock);
+	read_lock(&chan_list_lock);
 
-	sk_for_each(sk, node, &l2cap_sk_list.head) {
-		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+	list_for_each_entry(c, &chan_list, global_l) {
+		struct sock *sk = c->sk;
 
 		if (state && sk->sk_state != state)
 			continue;
 
-		if (chan->psm == psm) {
+		if (c->psm == psm) {
 			/* Exact match. */
-			if (!bacmp(&bt_sk(sk)->src, src))
-				break;
+			if (!bacmp(&bt_sk(sk)->src, src)) {
+				read_unlock_bh(&chan_list_lock);
+				return c;
+			}
 
 			/* Closest match */
 			if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
-				sk1 = sk;
+				c1 = c;
 		}
 	}
 
-	read_unlock(&l2cap_sk_list.lock);
+	read_unlock(&chan_list_lock);
 
-	return node ? sk : sk1;
+	return c1;
 }
 
 int l2cap_chan_connect(struct l2cap_chan *chan)
@@ -2079,22 +2088,26 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 {
 	struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
 	struct l2cap_conn_rsp rsp;
-	struct l2cap_chan *chan = NULL;
+	struct l2cap_chan *chan = NULL, *pchan;
 	struct sock *parent, *sk = NULL;
 	int result, status = L2CAP_CS_NO_INFO;
 
 	u16 dcid = 0, scid = __le16_to_cpu(req->scid);
 	__le16 psm = req->psm;
 
-	BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
+	BT_ERR("psm 0x%2.2x scid 0x%4.4x", psm, scid);
 
 	/* Check if we have socket listening on psm */
-	parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
-	if (!parent) {
+	pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
+	if (!pchan) {
 		result = L2CAP_CR_BAD_PSM;
 		goto sendresp;
 	}
 
+	BT_ERR("%p 0x%2.2x", pchan, pchan->psm);
+
+	parent = pchan->sk;
+
 	bh_lock_sock(parent);
 
 	/* Check if the ACL is secure enough (if not SDP) */
@@ -2117,7 +2130,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 	if (!sk)
 		goto response;
 
-	chan = l2cap_chan_alloc(sk);
+	chan = l2cap_chan_create(sk);
 	if (!chan) {
 		l2cap_sock_kill(sk);
 		goto response;
@@ -3745,11 +3758,14 @@ done:
 static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
 {
 	struct sock *sk;
+	struct l2cap_chan *chan;
 
-	sk = l2cap_get_sock_by_psm(0, psm, conn->src);
-	if (!sk)
+	chan = l2cap_global_chan_by_psm(0, psm, conn->src);
+	if (!chan)
 		goto drop;
 
+	sk = chan->sk;
+
 	bh_lock_sock(sk);
 
 	BT_DBG("sk %p, len %d", sk, skb->len);
@@ -3775,11 +3791,14 @@ done:
 static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
 {
 	struct sock *sk;
+	struct l2cap_chan *chan;
 
-	sk = l2cap_get_sock_by_scid(0, cid, conn->src);
-	if (!sk)
+	chan = l2cap_global_chan_by_scid(0, cid, conn->src);
+	if (!chan)
 		goto drop;
 
+	sk = chan->sk;
+
 	bh_lock_sock(sk);
 
 	BT_DBG("sk %p, len %d", sk, skb->len);
@@ -3846,8 +3865,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
 static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
 	int exact = 0, lm1 = 0, lm2 = 0;
-	register struct sock *sk;
-	struct hlist_node *node;
+	struct l2cap_chan *c;
 
 	if (type != ACL_LINK)
 		return -EINVAL;
@@ -3855,25 +3873,25 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 	BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
 
 	/* Find listening sockets and check their link_mode */
-	read_lock(&l2cap_sk_list.lock);
-	sk_for_each(sk, node, &l2cap_sk_list.head) {
-		struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+	read_lock(&chan_list_lock);
+	list_for_each_entry(c, &chan_list, global_l) {
+		struct sock *sk = c->sk;
 
 		if (sk->sk_state != BT_LISTEN)
 			continue;
 
 		if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
 			lm1 |= HCI_LM_ACCEPT;
-			if (chan->role_switch)
+			if (c->role_switch)
 				lm1 |= HCI_LM_MASTER;
 			exact++;
 		} else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
 			lm2 |= HCI_LM_ACCEPT;
-			if (chan->role_switch)
+			if (c->role_switch)
 				lm2 |= HCI_LM_MASTER;
 		}
 	}
-	read_unlock(&l2cap_sk_list.lock);
+	read_unlock(&chan_list_lock);
 
 	return exact ? lm1 : lm2;
 }
@@ -4126,25 +4144,22 @@ drop:
 
 static int l2cap_debugfs_show(struct seq_file *f, void *p)
 {
-	struct sock *sk;
-	struct hlist_node *node;
+	struct l2cap_chan *c;
 
-	read_lock_bh(&l2cap_sk_list.lock);
+	read_lock_bh(&chan_list_lock);
 
-	sk_for_each(sk, node, &l2cap_sk_list.head) {
-		struct l2cap_pinfo *pi = l2cap_pi(sk);
-		struct l2cap_chan *chan = pi->chan;
+	list_for_each_entry(c, &chan_list, global_l) {
+		struct sock *sk = c->sk;
 
 		seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
 					batostr(&bt_sk(sk)->src),
 					batostr(&bt_sk(sk)->dst),
-					sk->sk_state, __le16_to_cpu(chan->psm),
-					chan->scid, chan->dcid,
-					chan->imtu, chan->omtu, chan->sec_level,
-					chan->mode);
+					sk->sk_state, __le16_to_cpu(c->psm),
+					c->scid, c->dcid, c->imtu, c->omtu,
+					c->sec_level, c->mode);
 	}
 
-	read_unlock_bh(&l2cap_sk_list.lock);
+	read_unlock_bh(&chan_list_lock);
 
 	return 0;
 }
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index aca99cd..c98360d 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -808,8 +808,7 @@ void l2cap_sock_kill(struct sock *sk)
 
 	/* Kill poor orphan */
 
-	l2cap_chan_free(l2cap_pi(sk)->chan);
-	bt_sock_unlink(&l2cap_sk_list, sk);
+	l2cap_chan_destroy(l2cap_pi(sk)->chan);
 	sock_set_flag(sk, SOCK_DEAD);
 	sock_put(sk);
 }
@@ -1025,7 +1024,6 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, g
 
 	setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk);
 
-	bt_sock_link(&l2cap_sk_list, sk);
 	return sk;
 }
 
@@ -1052,7 +1050,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
 	if (!sk)
 		return -ENOMEM;
 
-	chan = l2cap_chan_alloc(sk);
+	chan = l2cap_chan_create(sk);
 	if (!chan) {
 		l2cap_sock_kill(sk);
 		return -ENOMEM;
-- 
1.7.5.rc1


^ permalink raw reply related

* [PATCH -v2 2/3] Bluetooth: Handle psm == 0 case inside l2cap_add_psm()
From: Gustavo F. Padovan @ 2011-04-28  5:26 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1303968420-12719-1-git-send-email-padovan@profusion.mobi>

When the user doesn't specify a psm we have the choose one for the
channel. Now we do this inside l2cap_add_psm().

Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
 include/net/bluetooth/l2cap.h |    1 -
 net/bluetooth/l2cap_core.c    |   32 ++++++++++++++++++++++++--------
 net/bluetooth/l2cap_sock.c    |   22 ----------------------
 3 files changed, 24 insertions(+), 31 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index f5f3c2c..fb3f90e 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -458,7 +458,6 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb);
 void l2cap_streaming_send(struct l2cap_chan *chan);
 int l2cap_ertm_send(struct l2cap_chan *chan);
 
-struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src);
 int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);
 int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid);
 
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 98ddd86..9e3f64f 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -135,7 +135,7 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn
 	return c;
 }
 
-struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
+static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
 {
 	struct sock *sk;
 	struct hlist_node *node;
@@ -153,19 +153,35 @@ found:
 
 int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
 {
+	int err;
+
 	write_lock_bh(&l2cap_sk_list.lock);
 
-	if (__l2cap_get_sock_by_addr(psm, src)) {
-		write_unlock_bh(&l2cap_sk_list.lock);
-		return -EADDRINUSE;
+	if (psm && __l2cap_get_sock_by_addr(psm, src)) {
+		err = -EADDRINUSE;
+		goto done;
 	}
 
-	chan->psm = psm;
-	chan->sport = psm;
+	if (psm) {
+		chan->psm = psm;
+		chan->sport = psm;
+		err = 0;
+	} else {
+		u16 p;
 
-	write_unlock_bh(&l2cap_sk_list.lock);
+		err = -EINVAL;
+		for (p = 0x1001; p < 0x1100; p += 2)
+			if (!__l2cap_get_sock_by_addr(cpu_to_le16(p), src)) {
+				chan->psm   = cpu_to_le16(p);
+				chan->sport = cpu_to_le16(p);
+				err = 0;
+				break;
+			}
+	}
 
-	return 0;
+done:
+	write_unlock_bh(&l2cap_sk_list.lock);
+	return err;
 }
 
 int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 2156dce..aca99cd 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -256,28 +256,6 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
 		goto done;
 	}
 
-	if (!chan->psm && !chan->scid) {
-		bdaddr_t *src = &bt_sk(sk)->src;
-		u16 psm;
-
-		err = -EINVAL;
-
-		write_lock_bh(&l2cap_sk_list.lock);
-
-		for (psm = 0x1001; psm < 0x1100; psm += 2)
-			if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
-				chan->psm   = cpu_to_le16(psm);
-				chan->sport = cpu_to_le16(psm);
-				err = 0;
-				break;
-			}
-
-		write_unlock_bh(&l2cap_sk_list.lock);
-
-		if (err < 0)
-			goto done;
-	}
-
 	sk->sk_max_ack_backlog = backlog;
 	sk->sk_ack_backlog = 0;
 	sk->sk_state = BT_LISTEN;
-- 
1.7.5.rc1


^ 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