summaryrefslogtreecommitdiffstats
path: root/freed-ora/current/F-12/git-bluetooth.patch
diff options
context:
space:
mode:
Diffstat (limited to 'freed-ora/current/F-12/git-bluetooth.patch')
-rw-r--r--freed-ora/current/F-12/git-bluetooth.patch3344
1 files changed, 3344 insertions, 0 deletions
diff --git a/freed-ora/current/F-12/git-bluetooth.patch b/freed-ora/current/F-12/git-bluetooth.patch
new file mode 100644
index 000000000..8ecc995c2
--- /dev/null
+++ b/freed-ora/current/F-12/git-bluetooth.patch
@@ -0,0 +1,3344 @@
+commit b1fb06830dc870d862f7f80e276130c0ab84d59f
+Author: Wei Yongjun <yjwei@cn.fujitsu.com>
+Date: Wed Feb 25 18:09:33 2009 +0800
+
+ Bluetooth: Remove some pointless conditionals before kfree_skb()
+
+ Remove some pointless conditionals before kfree_skb().
+
+ Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 7585b97a48180f754ebdade1be94092e36bef365
+Author: Wei Yongjun <yjwei@cn.fujitsu.com>
+Date: Wed Feb 25 18:29:52 2009 +0800
+
+ Bluetooth: Remove some pointless conditionals before kfree_skb()
+
+ Remove some pointless conditionals before kfree_skb().
+
+ Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 2ae9a6be5f476f3512839a4d11a8f432bfd2914c
+Author: Dave Young <hidave.darkstar@gmail.com>
+Date: Sat Feb 21 16:13:34 2009 +0800
+
+ Bluetooth: Move hci_conn_del_sysfs() back to avoid device destruct too early
+
+ The following commit introduce a regression:
+
+ commit 7d0db0a373195385a2e0b19d1f5e4b186fdcffac
+ Author: Marcel Holtmann <marcel@holtmann.org>
+ Date: Mon Jul 14 20:13:51 2008 +0200
+
+ [Bluetooth] Use a more unique bus name for connections
+
+ I get panic as following (by netconsole):
+
+ [ 2709.344034] usb 5-1: new full speed USB device using uhci_hcd and address 4
+ [ 2709.505776] usb 5-1: configuration #1 chosen from 1 choice
+ [ 2709.569207] Bluetooth: Generic Bluetooth USB driver ver 0.4
+ [ 2709.570169] usbcore: registered new interface driver btusb
+ [ 2845.742781] BUG: unable to handle kernel paging request at 6b6b6c2f
+ [ 2845.742958] IP: [<c015515c>] __lock_acquire+0x6c/0xa80
+ [ 2845.743087] *pde = 00000000
+ [ 2845.743206] Oops: 0002 [#1] SMP
+ [ 2845.743377] last sysfs file: /sys/class/bluetooth/hci0/hci0:6/type
+ [ 2845.743742] Modules linked in: btusb netconsole snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss rfcomm l2cap bluetooth vfat fuse snd_hda_codec_idt snd_hda_intel snd_hda_codec snd_hwdep snd_pcm pl2303 snd_timer psmouse usbserial snd 3c59x e100 serio_raw soundcore i2c_i801 intel_agp mii agpgart snd_page_alloc rtc_cmos rtc_core thermal processor rtc_lib button thermal_sys sg evdev
+ [ 2845.743742]
+ [ 2845.743742] Pid: 0, comm: swapper Not tainted (2.6.29-rc5-smp #54) Dell DM051
+ [ 2845.743742] EIP: 0060:[<c015515c>] EFLAGS: 00010002 CPU: 0
+ [ 2845.743742] EIP is at __lock_acquire+0x6c/0xa80
+ [ 2845.743742] EAX: 00000046 EBX: 00000046 ECX: 6b6b6b6b EDX: 00000002
+ [ 2845.743742] ESI: 6b6b6b6b EDI: 00000000 EBP: c064fd14 ESP: c064fcc8
+ [ 2845.743742] DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068
+ [ 2845.743742] Process swapper (pid: 0, ti=c064e000 task=c05d1400 task.ti=c064e000)
+ [ 2845.743742] Stack:
+ [ 2845.743742] c05d1400 00000002 c05d1400 00000001 00000002 00000000 f65388dc c05d1400
+ [ 2845.743742] 6b6b6b6b 00000292 c064fd0c c0153732 00000000 00000000 00000001 f700fa50
+ [ 2845.743742] 00000046 00000000 00000000 c064fd40 c0155be6 00000000 00000002 00000001
+ [ 2845.743742] Call Trace:
+ [ 2845.743742] [<c0153732>] ? trace_hardirqs_on_caller+0x72/0x1c0
+ [ 2845.743742] [<c0155be6>] ? lock_acquire+0x76/0xa0
+ [ 2845.743742] [<c03e1aad>] ? skb_dequeue+0x1d/0x70
+ [ 2845.743742] [<c046c885>] ? _spin_lock_irqsave+0x45/0x80
+ [ 2845.743742] [<c03e1aad>] ? skb_dequeue+0x1d/0x70
+ [ 2845.743742] [<c03e1aad>] ? skb_dequeue+0x1d/0x70
+ [ 2845.743742] [<c03e1f94>] ? skb_queue_purge+0x14/0x20
+ [ 2845.743742] [<f8171f5a>] ? hci_conn_del+0x10a/0x1c0 [bluetooth]
+ [ 2845.743742] [<f81399c9>] ? l2cap_disconn_ind+0x59/0xb0 [l2cap]
+ [ 2845.743742] [<f81795ce>] ? hci_conn_del_sysfs+0x8e/0xd0 [bluetooth]
+ [ 2845.743742] [<f8175758>] ? hci_event_packet+0x5f8/0x31c0 [bluetooth]
+ [ 2845.743742] [<c03dfe19>] ? sock_def_readable+0x59/0x80
+ [ 2845.743742] [<c046c14d>] ? _read_unlock+0x1d/0x20
+ [ 2845.743742] [<f8178aa9>] ? hci_send_to_sock+0xe9/0x1d0 [bluetooth]
+ [ 2845.743742] [<c015388b>] ? trace_hardirqs_on+0xb/0x10
+ [ 2845.743742] [<f816fa6a>] ? hci_rx_task+0x2ba/0x490 [bluetooth]
+ [ 2845.743742] [<c0133661>] ? tasklet_action+0x31/0xc0
+ [ 2845.743742] [<c013367c>] ? tasklet_action+0x4c/0xc0
+ [ 2845.743742] [<c0132eb7>] ? __do_softirq+0xa7/0x170
+ [ 2845.743742] [<c0116dec>] ? ack_apic_level+0x5c/0x1c0
+ [ 2845.743742] [<c0132fd7>] ? do_softirq+0x57/0x60
+ [ 2845.743742] [<c01333dc>] ? irq_exit+0x7c/0x90
+ [ 2845.743742] [<c01055bb>] ? do_IRQ+0x4b/0x90
+ [ 2845.743742] [<c01333d5>] ? irq_exit+0x75/0x90
+ [ 2845.743742] [<c010392c>] ? common_interrupt+0x2c/0x34
+ [ 2845.743742] [<c010a14f>] ? mwait_idle+0x4f/0x70
+ [ 2845.743742] [<c0101c05>] ? cpu_idle+0x65/0xb0
+ [ 2845.743742] [<c045731e>] ? rest_init+0x4e/0x60
+ [ 2845.743742] Code: 0f 84 69 02 00 00 83 ff 07 0f 87 1e 06 00 00 85 ff 0f 85 08 05 00 00 8b 4d cc 8b 49 04 85 c9 89 4d d4 0f 84 f7 04 00 00 8b 75 d4 <f0> ff 86 c4 00 00 00 89 f0 e8 56 a9 ff ff 85 c0 0f 85 6e 03 00
+ [ 2845.743742] EIP: [<c015515c>] __lock_acquire+0x6c/0xa80 SS:ESP 0068:c064fcc8
+ [ 2845.743742] ---[ end trace 4c985b38f022279f ]---
+ [ 2845.743742] Kernel panic - not syncing: Fatal exception in interrupt
+ [ 2845.743742] ------------[ cut here ]------------
+ [ 2845.743742] WARNING: at kernel/smp.c:329 smp_call_function_many+0x151/0x200()
+ [ 2845.743742] Hardware name: Dell DM051
+ [ 2845.743742] Modules linked in: btusb netconsole snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss rfcomm l2cap bluetooth vfat fuse snd_hda_codec_idt snd_hda_intel snd_hda_codec snd_hwdep snd_pcm pl2303 snd_timer psmouse usbserial snd 3c59x e100 serio_raw soundcore i2c_i801 intel_agp mii agpgart snd_page_alloc rtc_cmos rtc_core thermal processor rtc_lib button thermal_sys sg evdev
+ [ 2845.743742] Pid: 0, comm: swapper Tainted: G D 2.6.29-rc5-smp #54
+ [ 2845.743742] Call Trace:
+ [ 2845.743742] [<c012e076>] warn_slowpath+0x86/0xa0
+ [ 2845.743742] [<c015041b>] ? trace_hardirqs_off+0xb/0x10
+ [ 2845.743742] [<c0146384>] ? up+0x14/0x40
+ [ 2845.743742] [<c012e661>] ? release_console_sem+0x31/0x1e0
+ [ 2845.743742] [<c046c8ab>] ? _spin_lock_irqsave+0x6b/0x80
+ [ 2845.743742] [<c015041b>] ? trace_hardirqs_off+0xb/0x10
+ [ 2845.743742] [<c046c900>] ? _read_lock_irqsave+0x40/0x80
+ [ 2845.743742] [<c012e7f2>] ? release_console_sem+0x1c2/0x1e0
+ [ 2845.743742] [<c0146384>] ? up+0x14/0x40
+ [ 2845.743742] [<c015041b>] ? trace_hardirqs_off+0xb/0x10
+ [ 2845.743742] [<c046a3d7>] ? __mutex_unlock_slowpath+0x97/0x160
+ [ 2845.743742] [<c046a563>] ? mutex_trylock+0xb3/0x180
+ [ 2845.743742] [<c046a4a8>] ? mutex_unlock+0x8/0x10
+ [ 2845.743742] [<c015b991>] smp_call_function_many+0x151/0x200
+ [ 2845.743742] [<c010a1a0>] ? stop_this_cpu+0x0/0x40
+ [ 2845.743742] [<c015ba61>] smp_call_function+0x21/0x30
+ [ 2845.743742] [<c01137ae>] native_smp_send_stop+0x1e/0x50
+ [ 2845.743742] [<c012e0f5>] panic+0x55/0x110
+ [ 2845.743742] [<c01065a8>] oops_end+0xb8/0xc0
+ [ 2845.743742] [<c010668f>] die+0x4f/0x70
+ [ 2845.743742] [<c011a8c9>] do_page_fault+0x269/0x610
+ [ 2845.743742] [<c011a660>] ? do_page_fault+0x0/0x610
+ [ 2845.743742] [<c046cbaf>] error_code+0x77/0x7c
+ [ 2845.743742] [<c015515c>] ? __lock_acquire+0x6c/0xa80
+ [ 2845.743742] [<c0153732>] ? trace_hardirqs_on_caller+0x72/0x1c0
+ [ 2845.743742] [<c0155be6>] lock_acquire+0x76/0xa0
+ [ 2845.743742] [<c03e1aad>] ? skb_dequeue+0x1d/0x70
+ [ 2845.743742] [<c046c885>] _spin_lock_irqsave+0x45/0x80
+ [ 2845.743742] [<c03e1aad>] ? skb_dequeue+0x1d/0x70
+ [ 2845.743742] [<c03e1aad>] skb_dequeue+0x1d/0x70
+ [ 2845.743742] [<c03e1f94>] skb_queue_purge+0x14/0x20
+ [ 2845.743742] [<f8171f5a>] hci_conn_del+0x10a/0x1c0 [bluetooth]
+ [ 2845.743742] [<f81399c9>] ? l2cap_disconn_ind+0x59/0xb0 [l2cap]
+ [ 2845.743742] [<f81795ce>] ? hci_conn_del_sysfs+0x8e/0xd0 [bluetooth]
+ [ 2845.743742] [<f8175758>] hci_event_packet+0x5f8/0x31c0 [bluetooth]
+ [ 2845.743742] [<c03dfe19>] ? sock_def_readable+0x59/0x80
+ [ 2845.743742] [<c046c14d>] ? _read_unlock+0x1d/0x20
+ [ 2845.743742] [<f8178aa9>] ? hci_send_to_sock+0xe9/0x1d0 [bluetooth]
+ [ 2845.743742] [<c015388b>] ? trace_hardirqs_on+0xb/0x10
+ [ 2845.743742] [<f816fa6a>] hci_rx_task+0x2ba/0x490 [bluetooth]
+ [ 2845.743742] [<c0133661>] ? tasklet_action+0x31/0xc0
+ [ 2845.743742] [<c013367c>] tasklet_action+0x4c/0xc0
+ [ 2845.743742] [<c0132eb7>] __do_softirq+0xa7/0x170
+ [ 2845.743742] [<c0116dec>] ? ack_apic_level+0x5c/0x1c0
+ [ 2845.743742] [<c0132fd7>] do_softirq+0x57/0x60
+ [ 2845.743742] [<c01333dc>] irq_exit+0x7c/0x90
+ [ 2845.743742] [<c01055bb>] do_IRQ+0x4b/0x90
+ [ 2845.743742] [<c01333d5>] ? irq_exit+0x75/0x90
+ [ 2845.743742] [<c010392c>] common_interrupt+0x2c/0x34
+ [ 2845.743742] [<c010a14f>] ? mwait_idle+0x4f/0x70
+ [ 2845.743742] [<c0101c05>] cpu_idle+0x65/0xb0
+ [ 2845.743742] [<c045731e>] rest_init+0x4e/0x60
+ [ 2845.743742] ---[ end trace 4c985b38f02227a0 ]---
+ [ 2845.743742] ------------[ cut here ]------------
+ [ 2845.743742] WARNING: at kernel/smp.c:226 smp_call_function_single+0x8e/0x110()
+ [ 2845.743742] Hardware name: Dell DM051
+ [ 2845.743742] Modules linked in: btusb netconsole snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss rfcomm l2cap bluetooth vfat fuse snd_hda_codec_idt snd_hda_intel snd_hda_codec snd_hwdep snd_pcm pl2303 snd_timer psmouse usbserial snd 3c59x e100 serio_raw soundcore i2c_i801 intel_agp mii agpgart snd_page_alloc rtc_cmos rtc_core thermal processor rtc_lib button thermal_sys sg evdev
+ [ 2845.743742] Pid: 0, comm: swapper Tainted: G D W 2.6.29-rc5-smp #54
+ [ 2845.743742] Call Trace:
+ [ 2845.743742] [<c012e076>] warn_slowpath+0x86/0xa0
+ [ 2845.743742] [<c012e000>] ? warn_slowpath+0x10/0xa0
+ [ 2845.743742] [<c015041b>] ? trace_hardirqs_off+0xb/0x10
+ [ 2845.743742] [<c0146384>] ? up+0x14/0x40
+ [ 2845.743742] [<c012e661>] ? release_console_sem+0x31/0x1e0
+ [ 2845.743742] [<c046c8ab>] ? _spin_lock_irqsave+0x6b/0x80
+ [ 2845.743742] [<c015041b>] ? trace_hardirqs_off+0xb/0x10
+ [ 2845.743742] [<c046c900>] ? _read_lock_irqsave+0x40/0x80
+ [ 2845.743742] [<c012e7f2>] ? release_console_sem+0x1c2/0x1e0
+ [ 2845.743742] [<c0146384>] ? up+0x14/0x40
+ [ 2845.743742] [<c015b7be>] smp_call_function_single+0x8e/0x110
+ [ 2845.743742] [<c010a1a0>] ? stop_this_cpu+0x0/0x40
+ [ 2845.743742] [<c026d23f>] ? cpumask_next_and+0x1f/0x40
+ [ 2845.743742] [<c015b95a>] smp_call_function_many+0x11a/0x200
+ [ 2845.743742] [<c010a1a0>] ? stop_this_cpu+0x0/0x40
+ [ 2845.743742] [<c015ba61>] smp_call_function+0x21/0x30
+ [ 2845.743742] [<c01137ae>] native_smp_send_stop+0x1e/0x50
+ [ 2845.743742] [<c012e0f5>] panic+0x55/0x110
+ [ 2845.743742] [<c01065a8>] oops_end+0xb8/0xc0
+ [ 2845.743742] [<c010668f>] die+0x4f/0x70
+ [ 2845.743742] [<c011a8c9>] do_page_fault+0x269/0x610
+ [ 2845.743742] [<c011a660>] ? do_page_fault+0x0/0x610
+ [ 2845.743742] [<c046cbaf>] error_code+0x77/0x7c
+ [ 2845.743742] [<c015515c>] ? __lock_acquire+0x6c/0xa80
+ [ 2845.743742] [<c0153732>] ? trace_hardirqs_on_caller+0x72/0x1c0
+ [ 2845.743742] [<c0155be6>] lock_acquire+0x76/0xa0
+ [ 2845.743742] [<c03e1aad>] ? skb_dequeue+0x1d/0x70
+ [ 2845.743742] [<c046c885>] _spin_lock_irqsave+0x45/0x80
+ [ 2845.743742] [<c03e1aad>] ? skb_dequeue+0x1d/0x70
+ [ 2845.743742] [<c03e1aad>] skb_dequeue+0x1d/0x70
+ [ 2845.743742] [<c03e1f94>] skb_queue_purge+0x14/0x20
+ [ 2845.743742] [<f8171f5a>] hci_conn_del+0x10a/0x1c0 [bluetooth]
+ [ 2845.743742] [<f81399c9>] ? l2cap_disconn_ind+0x59/0xb0 [l2cap]
+ [ 2845.743742] [<f81795ce>] ? hci_conn_del_sysfs+0x8e/0xd0 [bluetooth]
+ [ 2845.743742] [<f8175758>] hci_event_packet+0x5f8/0x31c0 [bluetooth]
+ [ 2845.743742] [<c03dfe19>] ? sock_def_readable+0x59/0x80
+ [ 2845.743742] [<c046c14d>] ? _read_unlock+0x1d/0x20
+ [ 2845.743742] [<f8178aa9>] ? hci_send_to_sock+0xe9/0x1d0 [bluetooth]
+ [ 2845.743742] [<c015388b>] ? trace_hardirqs_on+0xb/0x10
+ [ 2845.743742] [<f816fa6a>] hci_rx_task+0x2ba/0x490 [bluetooth]
+ [ 2845.743742] [<c0133661>] ? tasklet_action+0x31/0xc0
+ [ 2845.743742] [<c013367c>] tasklet_action+0x4c/0xc0
+ [ 2845.743742] [<c0132eb7>] __do_softirq+0xa7/0x170
+ [ 2845.743742] [<c0116dec>] ? ack_apic_level+0x5c/0x1c0
+ [ 2845.743742] [<c0132fd7>] do_softirq+0x57/0x60
+ [ 2845.743742] [<c01333dc>] irq_exit+0x7c/0x90
+ [ 2845.743742] [<c01055bb>] do_IRQ+0x4b/0x90
+ [ 2845.743742] [<c01333d5>] ? irq_exit+0x75/0x90
+ [ 2845.743742] [<c010392c>] common_interrupt+0x2c/0x34
+ [ 2845.743742] [<c010a14f>] ? mwait_idle+0x4f/0x70
+ [ 2845.743742] [<c0101c05>] cpu_idle+0x65/0xb0
+ [ 2845.743742] [<c045731e>] rest_init+0x4e/0x60
+ [ 2845.743742] ---[ end trace 4c985b38f02227a1 ]---
+ [ 2845.743742] Rebooting in 3 seconds..
+
+ My logitec bluetooth mouse trying connect to pc, but
+ pc side reject the connection again and again. then panic happens.
+
+ The reason is due to hci_conn_del_sysfs now called in hci_event_packet,
+ the del work is done in a workqueue, so it's possible done before
+ skb_queue_purge called.
+
+ I move the hci_conn_del_sysfs after skb_queue_purge just as that before
+ marcel's commit.
+
+ Remove the hci_conn_del_sysfs in hci_conn_hash_flush as well due to
+ hci_conn_del will deal with the work.
+
+ Signed-off-by: Dave Young <hidave.darkstar@gmail.com>
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 2526d3d8b2f671a7d36cc486af984052cd5a690f
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Fri Feb 20 20:54:06 2009 +0100
+
+ Bluetooth: Permit BT_SECURITY also for L2CAP raw sockets
+
+ Userspace pairing code can be simplified if it doesn't have to fall
+ back to using L2CAP_LM in the case of L2CAP raw sockets. This patch
+ allows the BT_SECURITY socket option to be used for these sockets.
+
+ Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com>
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 37e62f5516cfb210e64fe53457932df4341b0ad1
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Tue Feb 17 21:49:33 2009 +0100
+
+ Bluetooth: Fix RFCOMM usage of in-kernel L2CAP sockets
+
+ The CID value of L2CAP sockets need to be set to zero. All userspace
+ applications do this via memset() on the sockaddr_l2 structure. The
+ RFCOMM implementation uses in-kernel L2CAP sockets and so it has to
+ make sure that l2_cid is set to zero.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 2a517ca687232adc8f14893730644da712010ffc
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Mon Feb 16 03:20:31 2009 +0100
+
+ Bluetooth: Disallow usage of L2CAP CID setting for now
+
+ In the future the L2CAP layer will have full support for fixed channels
+ and right now it already can export the channel assignment, but for the
+ functions bind() and connect() the usage of only CID 0 is allowed. This
+ allows an easy detection if the kernel supports fixed channels or not,
+ because otherwise it would impossible for application to tell.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 8bf4794174659b06d43cc5e290cd384757374613
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Mon Feb 16 02:59:49 2009 +0100
+
+ Bluetooth: Change RFCOMM to use BT_CONNECT2 for BT_DEFER_SETUP
+
+ When BT_DEFER_SETUP is enabled on a RFCOMM socket, then switch its
+ current state from BT_OPEN to BT_CONNECT2. This gives the Bluetooth
+ core a unified way to handle L2CAP and RFCOMM sockets. The BT_CONNECT2
+ state is designated for incoming connections.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit d5f2d2be68876f65dd051b978a7b66265fde9ffd
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Mon Feb 16 02:57:30 2009 +0100
+
+ Bluetooth: Fix poll() misbehavior when using BT_DEFER_SETUP
+
+ When BT_DEFER_SETUP has been enabled on a Bluetooth socket it keeps
+ signaling POLLIN all the time. This is a wrong behavior. The POLLIN
+ should only be signaled if the client socket is in BT_CONNECT2 state
+ and the parent has been BT_DEFER_SETUP enabled.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 96a3183322cba1a2846771b067c99b9d6f481263
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Feb 12 16:23:03 2009 +0100
+
+ Bluetooth: Set authentication requirement before requesting it
+
+ The authentication requirement got only updated when the security level
+ increased. This is a wrong behavior. The authentication requirement is
+ read by the Bluetooth daemon to make proper decisions when handling the
+ IO capabilities exchange. So set the value that is currently expected by
+ the higher layers like L2CAP and RFCOMM.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 00ae4af91d8c5b6814e2bb3bfaaf743845f989eb
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Feb 12 16:19:45 2009 +0100
+
+ Bluetooth: Fix authentication requirements for L2CAP security check
+
+ The L2CAP layer can trigger the authentication via an ACL connection or
+ later on to increase the security level. When increasing the security
+ level it didn't use the same authentication requirements when triggering
+ a new ACL connection. Make sure that exactly the same authentication
+ requirements are used. The only exception here are the L2CAP raw sockets
+ which are only used for dedicated bonding.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 2950f21acb0f6b8fcd964485c2ebf1e06545ac20
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Feb 12 14:02:50 2009 +0100
+
+ Bluetooth: Ask upper layers for HCI disconnect reason
+
+ Some of the qualification tests demand that in case of failures in L2CAP
+ the HCI disconnect should indicate a reason why L2CAP fails. This is a
+ bluntly layer violation since multiple L2CAP connections could be using
+ the same ACL and thus forcing a disconnect reason is not a good idea.
+
+ To comply with the Bluetooth test specification, the disconnect reason
+ is now stored in the L2CAP connection structure and every time a new
+ L2CAP channel is added it will set back to its default. So only in the
+ case where the L2CAP channel with the disconnect reason is really the
+ last one, it will propagated to the HCI layer.
+
+ The HCI layer has been extended with a disconnect indication that allows
+ it to ask upper layers for a disconnect reason. The upper layer must not
+ support this callback and in that case it will nicely default to the
+ existing behavior. If an upper layer like L2CAP can provide a disconnect
+ reason that one will be used to disconnect the ACL or SCO link.
+
+ No modification to the ACL disconnect timeout have been made. So in case
+ of Linux to Linux connection the initiator will disconnect the ACL link
+ before the acceptor side can signal the specific disconnect reason. That
+ is perfectly fine since Linux doesn't make use of this value anyway. The
+ L2CAP layer has a perfect valid error code for rejecting connection due
+ to a security violation. It is unclear why the Bluetooth specification
+ insists on having specific HCI disconnect reason.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit f29972de8e7476706ab3c01304a505e7c95d9040
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Feb 12 05:07:45 2009 +0100
+
+ Bluetooth: Add CID field to L2CAP socket address structure
+
+ In preparation for L2CAP fixed channel support, the CID value of a
+ L2CAP connection needs to be accessible via the socket interface. The
+ CID is the connection identifier and exists as source and destination
+ value. So extend the L2CAP socket address structure with this field and
+ change getsockname() and getpeername() to fill it in.
+
+ The bind() and connect() functions have been modified to handle L2CAP
+ socket address structures of variable sizes. This makes them future
+ proof if additional fields need to be added.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit e1027a7c69700301d14db03d2e049ee60c4f92df
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Mon Feb 9 09:18:02 2009 +0100
+
+ Bluetooth: Request L2CAP fixed channel list if available
+
+ If the extended features mask indicates support for fixed channels,
+ request the list of available fixed channels. This also enables the
+ fixed channel features bit so remote implementations can request
+ information about it. Currently only the signal channel will be
+ listed.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 435fef20acfc48f46476abad55b0cd3aa47b8365
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Mon Feb 9 03:55:28 2009 +0100
+
+ Bluetooth: Don't enforce authentication for L2CAP PSM 1 and 3
+
+ The recommendation for the L2CAP PSM 1 (SDP) is to not use any kind
+ of authentication or encryption. So don't trigger authentication
+ for incoming and outgoing SDP connections.
+
+ For L2CAP PSM 3 (RFCOMM) there is no clear requirement, but with
+ Bluetooth 2.1 the initiator is required to enable authentication
+ and encryption first and this gets enforced. So there is no need
+ to trigger an additional authentication step. The RFCOMM service
+ security will make sure that a secure enough link key is present.
+
+ When the encryption gets enabled after the SDP connection setup,
+ then switch the security level from SDP to low security.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 6a8d3010b313d99adbb28f1826fac0234395bb26
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Fri Feb 6 23:56:36 2009 +0100
+
+ Bluetooth: Fix double L2CAP connection request
+
+ If the remote L2CAP server uses authentication pending stage and
+ encryption is enabled it can happen that a L2CAP connection request is
+ sent twice due to a race condition in the connection state machine.
+
+ When the remote side indicates any kind of connection pending, then
+ track this state and skip sending of L2CAP commands for this period.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 984947dc64f82bc6cafa4d84ba1a139718f634a8
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Fri Feb 6 23:35:19 2009 +0100
+
+ Bluetooth: Fix race condition with L2CAP information request
+
+ When two L2CAP connections are requested quickly after the ACL link has
+ been established there exists a window for a race condition where a
+ connection request is sent before the information response has been
+ received. Any connection request should only be sent after an exchange
+ of the extended features mask has been finished.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 657e17b03c80bec817975984d221bef716f83558
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Fri Feb 6 19:45:36 2009 +0100
+
+ Bluetooth: Set authentication requirements if not available
+
+ When no authentication requirements are selected, but an outgoing or
+ incoming connection has requested any kind of security enforcement,
+ then set these authentication requirements.
+
+ This ensures that the userspace always gets informed about the
+ authentication requirements (if available). Only when no security
+ enforcement has happened, the kernel will signal invalid requirements.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 0684e5f9fb9e3f7e168ab831dfca693bcb44805b
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Mon Feb 9 02:48:38 2009 +0100
+
+ Bluetooth: Use general bonding whenever possible
+
+ When receiving incoming connection to specific services, always use
+ general bonding. This ensures that the link key gets stored and can be
+ used for further authentications.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit efc7688b557dd1be10eead7399b315efcb1dbc74
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Fri Feb 6 09:13:37 2009 +0100
+
+ Bluetooth: Add SCO fallback for eSCO connection attempts
+
+ When attempting to setup eSCO connections it can happen that some link
+ manager implementations fail to properly negotiate the eSCO parameters
+ and thus fail the eSCO setup. Normally the link manager is responsible
+ for the negotiation of the parameters and actually fallback to SCO if
+ no agreement can be reached. In cases where the link manager is just too
+ stupid, then at least try to establish a SCO link if eSCO fails.
+
+ For the Bluetooth devices with EDR support this includes handling packet
+ types of EDR basebands. This is particular tricky since for the EDR the
+ logic of enabling/disabling one specific packet type is turned around.
+ This fix contains an extra bitmask to disable eSCO EDR packet when
+ trying to fallback to a SCO connection.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 255c76014af74165428e7aa16414b857e2bdccf2
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Wed Feb 4 21:07:19 2009 +0100
+
+ Bluetooth: Don't check encryption for L2CAP raw sockets
+
+ For L2CAP sockets with medium and high security requirement a missing
+ encryption will enforce the closing of the link. For the L2CAP raw
+ sockets this is not needed, so skip that check.
+
+ This fixes a crash when pairing Bluetooth 2.0 (and earlier) devices
+ since the L2CAP state machine got confused and then locked up the whole
+ system.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 43c2e57f94c15744495fee564610aa24602b3824
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Wed Feb 4 17:41:38 2009 +0100
+
+ Bluetooth: Submit bulk URBs along with interrupt URBs
+
+ Submitting the bulk URBs for ACL data transfers only on demand has no
+ real benefit compared to just submit them when a Bluetooth device gets
+ opened. So when submitting the interrupt URBs for HCI events, just
+ submit the bulk URBs, too.
+
+ This solves a problem with some Bluetooth USB dongles that has been
+ reported over the last few month. These devices require that the bulk
+ URBs are actually present. These devices are really broken, but there
+ is nothing we can do about it.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 6e1031a40029492c10509e8c3dcac9b611438ccb
+Author: Jaikumar Ganesh <jaikumar@google.com>
+Date: Mon Feb 2 18:03:57 2009 -0800
+
+ Bluetooth: When encryption is dropped, do not send RFCOMM packets
+
+ During a role change with pre-Bluetooth 2.1 devices, the remote side drops
+ the encryption of the RFCOMM connection. We allow a grace period for the
+ encryption to be re-established, before dropping the connection. During
+ this grace period, the RFCOMM_SEC_PENDING flag is set. Check this flag
+ before sending RFCOMM packets.
+
+ Signed-off-by: Jaikumar Ganesh <jaikumar@google.com>
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 34a55eda483e8177c9044f93fd2c9107f02bf1c7
+Author: Andre Haupt <andre@bitwigglers.org>
+Date: Mon Feb 2 14:45:11 2009 -0800
+
+ Bluetooth: Eliminate a sparse warning in bt3c driver
+
+ This eliminates a sparse warning that symbol 'stat' shadows an earlier one.
+
+ Signed-off-by: Andre Haupt <andre@bitwigglers.org>
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit dd2efd03b49d56ae795c71335bc7358022514c32
+Author: Dave Young <hidave.darkstar@gmail.com>
+Date: Sat Jan 31 13:51:15 2009 +0800
+
+ Bluetooth: Remove CONFIG_DEBUG_LOCK_ALLOC ifdefs
+
+ Due to lockdep changes, the CONFIG_DEBUG_LOCK_ALLOC ifdef is not needed
+ now. So just remove it here.
+
+ The following commit fixed the !lockdep build warnings:
+
+ commit e8f6fbf62de37cbc2e179176ac7010d5f4396b67
+ Author: Ingo Molnar <mingo@elte.hu>
+ Date: Wed Nov 12 01:38:36 2008 +0000
+
+ lockdep: include/linux/lockdep.h - fix warning in net/bluetooth/af_bluetooth.c
+
+ Signed-off-by: Dave Young <hidave.darkstar@gmail.com>
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 5f9018af004fa8635bbbe3ab2dc61e8a686edfaa
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Fri Jan 16 10:09:50 2009 +0100
+
+ Bluetooth: Update version numbers
+
+ With the support for the enhanced security model and the support for
+ deferring connection setup, it is a good idea to increase various
+ version numbers.
+
+ This is purely cosmetic and has no effect on the behavior, but can
+ be really helpful when debugging problems in different kernel versions.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 0588d94fd7e414367a7ae517569d2222441c255f
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Fri Jan 16 10:06:13 2009 +0100
+
+ Bluetooth: Restrict application of socket options
+
+ The new socket options should only be evaluated for SOL_BLUETOOTH level
+ and not for every other level. Previously this causes some minor issues
+ when detecting if a kernel with certain features is available.
+
+ Also restrict BT_SECURITY to SOCK_SEQPACKET for L2CAP and SOCK_STREAM for
+ the RFCOMM protocol.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit f62e4323ab43c59e7cd7f72c1eb392d7c767ce5a
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Jan 15 21:58:44 2009 +0100
+
+ Bluetooth: Disconnect L2CAP connections without encryption
+
+ For L2CAP connections with high security setting, the link will be
+ immediately dropped when the encryption gets disabled. For L2CAP
+ connections with medium security there will be grace period where
+ the remote device has the chance to re-enable encryption. If it
+ doesn't happen then the link will also be disconnected.
+
+ The requirement for the grace period with medium security comes from
+ Bluetooth 2.0 and earlier devices that require role switching.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 8c84b83076b5062f59b6167cdda90d9e5124aa71
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Fri Jan 16 08:17:51 2009 +0100
+
+ Bluetooth: Pause RFCOMM TX when encryption drops
+
+ A role switch with devices following the Bluetooth pre-2.1 standards
+ or without Encryption Pause and Resume support is not possible if
+ encryption is enabled. Most newer headsets require the role switch,
+ but also require that the connection is encrypted.
+
+ For connections with a high security mode setting, the link will be
+ immediately dropped. When the connection uses medium security mode
+ setting, then a grace period is introduced where the TX is halted and
+ the remote device gets a change to re-enable encryption after the
+ role switch. If not re-enabled the link will be dropped.
+
+ Based on initial work by Ville Tervo <ville.tervo@nokia.com>
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 9f2c8a03fbb3048cf38b158f87aa0c3c09bca084
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Jan 15 21:58:40 2009 +0100
+
+ Bluetooth: Replace RFCOMM link mode with security level
+
+ Change the RFCOMM internals to use the new security levels and remove
+ the link mode details.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 2af6b9d518ddfbc4d6990d5f9c9b1a05341c1cef
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Jan 15 21:58:38 2009 +0100
+
+ Bluetooth: Replace L2CAP link mode with security level
+
+ Change the L2CAP internals to use the new security levels and remove
+ the link mode details.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 8c1b235594fbab9a13240a1dac12ea9fd99b6440
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Jan 15 21:58:04 2009 +0100
+
+ Bluetooth: Add enhanced security model for Simple Pairing
+
+ The current security model is based around the flags AUTH, ENCRYPT and
+ SECURE. Starting with support for the Bluetooth 2.1 specification this is
+ no longer sufficient. The different security levels are now defined as
+ SDP, LOW, MEDIUM and SECURE.
+
+ Previously it was possible to set each security independently, but this
+ actually doesn't make a lot of sense. For Bluetooth the encryption depends
+ on a previous successful authentication. Also you can only update your
+ existing link key if you successfully created at least one before. And of
+ course the update of link keys without having proper encryption in place
+ is a security issue.
+
+ The new security levels from the Bluetooth 2.1 specification are now
+ used internally. All old settings are mapped to the new values and this
+ way it ensures that old applications still work. The only limitation
+ is that it is no longer possible to set authentication without also
+ enabling encryption. No application should have done this anyway since
+ this is actually a security issue. Without encryption the integrity of
+ the authentication can't be guaranteed.
+
+ As default for a new L2CAP or RFCOMM connection, the LOW security level
+ is used. The only exception here are the service discovery sessions on
+ PSM 1 where SDP level is used. To have similar security strength as with
+ a Bluetooth 2.0 and before combination key, the MEDIUM level should be
+ used. This is according to the Bluetooth specification. The MEDIUM level
+ will not require any kind of man-in-the-middle (MITM) protection. Only
+ the HIGH security level will require this.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit c89b6e6bda4c8021195778f47567d0cc9dbfe7ec
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Jan 15 21:57:03 2009 +0100
+
+ Bluetooth: Fix SCO state handling for incoming connections
+
+ When the remote device supports only SCO connections, on receipt of
+ the HCI_EV_CONN_COMPLETE event packet, the connect state is changed to
+ BT_CONNECTED, but the socket state is not updated. Hence, the connect()
+ call times out even though the SCO connection has been successfully
+ established.
+
+ Based on a report by Jaikumar Ganesh <jaikumar@google.com>
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 71aeeaa1fd88fe7446391e0553336f0e0c2cfe6a
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Jan 15 21:57:02 2009 +0100
+
+ Bluetooth: Reject incoming SCO connections without listeners
+
+ All SCO and eSCO connection are auto-accepted no matter if there is a
+ corresponding listening socket for them. This patch changes this and
+ connection requests for SCO and eSCO without any socket are rejected.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit f66dc81f44d918ee1aa1a9d821bb2f25c7592bc0
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Jan 15 21:57:00 2009 +0100
+
+ Bluetooth: Add support for deferring L2CAP connection setup
+
+ In order to decide if listening L2CAP sockets should be accept()ed
+ the BD_ADDR of the remote device needs to be known. This patch adds
+ a socket option which defines a timeout for deferring the actual
+ connection setup.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit bb23c0ab824653be4aa7dfca15b07b3059717004
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Jan 15 21:56:48 2009 +0100
+
+ Bluetooth: Add support for deferring RFCOMM connection setup
+
+ In order to decide if listening RFCOMM sockets should be accept()ed
+ the BD_ADDR of the remote device needs to be known. This patch adds
+ a socket option which defines a timeout for deferring the actual
+ connection setup.
+
+ The connection setup is done after reading from the socket for the
+ first time. Until then writing to the socket returns ENOTCONN.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit c4f912e155504e94dd4f3d63c378dab0ff03dbda
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Jan 15 21:52:16 2009 +0100
+
+ Bluetooth: Add global deferred socket parameter
+
+ The L2CAP and RFCOMM applications require support for authorization
+ and the ability of rejecting incoming connection requests. The socket
+ interface is not really able to support this.
+
+ This patch does the ground work for a socket option to defer connection
+ setup. Setting this option allows calling of accept() and then the
+ first read() will trigger the final connection setup. Calling close()
+ would reject the connection.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit d58daf42d29a3a4a4d4be46cf47ceee096789680
+Author: Marcel Holtmann <marcel@holtmann.org>
+Date: Thu Jan 15 21:52:14 2009 +0100
+
+ Bluetooth: Preparation for usage of SOL_BLUETOOTH
+
+ The socket option levels SOL_L2CAP, SOL_RFOMM and SOL_SCO are currently
+ in use by various Bluetooth applications. Going forward the common
+ option level SOL_BLUETOOTH should be used. This patch prepares the clean
+ split of the old and new option levels while keeping everything backward
+ compatibility.
+
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+commit 91aa35a5aa3540223066bf6b51c935418c63a35d
+Author: Victor Shcherbatyuk <victor.shcherbatyuk@tomtom.com>
+Date: Thu Jan 15 21:52:12 2009 +0100
+
+ Bluetooth: Fix issue with return value of rfcomm_sock_sendmsg()
+
+ In case of connection failures the rfcomm_sock_sendmsg() should return
+ an error and not a 0 value.
+
+ Signed-off-by: Victor Shcherbatyuk <victor.shcherbatyuk@tomtom.com>
+ Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+
+diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
+index d3f14be..2a00707 100644
+--- a/drivers/bluetooth/bfusb.c
++++ b/drivers/bluetooth/bfusb.c
+@@ -257,8 +257,7 @@ static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned ch
+
+ if (hdr & 0x10) {
+ BT_ERR("%s error in block", data->hdev->name);
+- if (data->reassembly)
+- kfree_skb(data->reassembly);
++ kfree_skb(data->reassembly);
+ data->reassembly = NULL;
+ return -EIO;
+ }
+diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
+index ff195c2..d58e22b 100644
+--- a/drivers/bluetooth/bt3c_cs.c
++++ b/drivers/bluetooth/bt3c_cs.c
+@@ -359,9 +359,9 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
+ BT_ERR("Very strange (stat=0x%04x)", stat);
+ } else if ((stat & 0xff) != 0xff) {
+ if (stat & 0x0020) {
+- int stat = bt3c_read(iobase, 0x7002) & 0x10;
++ int status = bt3c_read(iobase, 0x7002) & 0x10;
+ BT_INFO("%s: Antenna %s", info->hdev->name,
+- stat ? "out" : "in");
++ status ? "out" : "in");
+ }
+ if (stat & 0x0001)
+ bt3c_receive(info);
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index b5fbda6..e70c57e 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -35,7 +35,7 @@
+ #include <net/bluetooth/bluetooth.h>
+ #include <net/bluetooth/hci_core.h>
+
+-#define VERSION "0.4"
++#define VERSION "0.5"
+
+ static int ignore_dga;
+ static int ignore_csr;
+@@ -171,6 +171,7 @@ struct btusb_data {
+
+ __u8 cmdreq_type;
+
++ unsigned int sco_num;
+ int isoc_altsetting;
+ int suspend_count;
+ };
+@@ -496,11 +497,23 @@ static int btusb_open(struct hci_dev *hdev)
+ return 0;
+
+ err = btusb_submit_intr_urb(hdev, GFP_KERNEL);
++ if (err < 0)
++ goto failed;
++
++ err = btusb_submit_bulk_urb(hdev, GFP_KERNEL);
+ if (err < 0) {
+- clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+- clear_bit(HCI_RUNNING, &hdev->flags);
++ usb_kill_anchored_urbs(&data->intr_anchor);
++ goto failed;
+ }
+
++ set_bit(BTUSB_BULK_RUNNING, &data->flags);
++ btusb_submit_bulk_urb(hdev, GFP_KERNEL);
++
++ return 0;
++
++failed:
++ clear_bit(BTUSB_INTR_RUNNING, &data->flags);
++ clear_bit(HCI_RUNNING, &hdev->flags);
+ return err;
+ }
+
+@@ -655,19 +668,10 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
+
+ BT_DBG("%s evt %d", hdev->name, evt);
+
+- if (hdev->conn_hash.acl_num > 0) {
+- if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
+- if (btusb_submit_bulk_urb(hdev, GFP_ATOMIC) < 0)
+- clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+- else
+- btusb_submit_bulk_urb(hdev, GFP_ATOMIC);
+- }
+- } else {
+- clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+- usb_unlink_anchored_urbs(&data->bulk_anchor);
++ if (hdev->conn_hash.sco_num != data->sco_num) {
++ data->sco_num = hdev->conn_hash.sco_num;
++ schedule_work(&data->work);
+ }
+-
+- schedule_work(&data->work);
+ }
+
+ static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting)
+@@ -982,9 +986,11 @@ static int btusb_resume(struct usb_interface *intf)
+ }
+
+ if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) {
+- if (btusb_submit_bulk_urb(hdev, GFP_NOIO) < 0)
++ err = btusb_submit_bulk_urb(hdev, GFP_NOIO);
++ if (err < 0) {
+ clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+- else
++ return err;
++ } else
+ btusb_submit_bulk_urb(hdev, GFP_NOIO);
+ }
+
+diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
+index b0fafb0..c0ce813 100644
+--- a/drivers/bluetooth/hci_h4.c
++++ b/drivers/bluetooth/hci_h4.c
+@@ -102,8 +102,7 @@ static int h4_close(struct hci_uart *hu)
+
+ skb_queue_purge(&h4->txq);
+
+- if (h4->rx_skb)
+- kfree_skb(h4->rx_skb);
++ kfree_skb(h4->rx_skb);
+
+ hu->priv = NULL;
+ kfree(h4);
+diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
+index b91d45a..5c65014 100644
+--- a/drivers/bluetooth/hci_ll.c
++++ b/drivers/bluetooth/hci_ll.c
+@@ -163,8 +163,7 @@ static int ll_close(struct hci_uart *hu)
+ skb_queue_purge(&ll->tx_wait_q);
+ skb_queue_purge(&ll->txq);
+
+- if (ll->rx_skb)
+- kfree_skb(ll->rx_skb);
++ kfree_skb(ll->rx_skb);
+
+ hu->priv = NULL;
+
+diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
+index a04f846..3ad5390 100644
+--- a/include/net/bluetooth/bluetooth.h
++++ b/include/net/bluetooth/bluetooth.h
+@@ -53,6 +53,17 @@
+ #define SOL_SCO 17
+ #define SOL_RFCOMM 18
+
++#define BT_SECURITY 4
++struct bt_security {
++ __u8 level;
++};
++#define BT_SECURITY_SDP 0
++#define BT_SECURITY_LOW 1
++#define BT_SECURITY_MEDIUM 2
++#define BT_SECURITY_HIGH 3
++
++#define BT_DEFER_SETUP 7
++
+ #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
+ #define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
+ #define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
+@@ -108,6 +119,7 @@ struct bt_sock {
+ bdaddr_t dst;
+ struct list_head accept_q;
+ struct sock *parent;
++ u32 defer_setup;
+ };
+
+ struct bt_sock_list {
+diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
+index 3645139..f69f015 100644
+--- a/include/net/bluetooth/hci.h
++++ b/include/net/bluetooth/hci.h
+@@ -133,8 +133,13 @@ enum {
+ #define ESCO_EV3 0x0008
+ #define ESCO_EV4 0x0010
+ #define ESCO_EV5 0x0020
++#define ESCO_2EV3 0x0040
++#define ESCO_3EV3 0x0080
++#define ESCO_2EV5 0x0100
++#define ESCO_3EV5 0x0200
+
+ #define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
++#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
+
+ /* ACL flags */
+ #define ACL_CONT 0x01
+@@ -176,6 +181,9 @@ enum {
+ #define LMP_EV5 0x02
+
+ #define LMP_SNIFF_SUBR 0x02
++#define LMP_EDR_ESCO_2M 0x20
++#define LMP_EDR_ESCO_3M 0x40
++#define LMP_EDR_3S_ESCO 0x80
+
+ #define LMP_SIMPLE_PAIR 0x08
+
+diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
+index 46a43b7..01f9316 100644
+--- a/include/net/bluetooth/hci_core.h
++++ b/include/net/bluetooth/hci_core.h
+@@ -169,6 +169,7 @@ struct hci_conn {
+ __u16 link_policy;
+ __u32 link_mode;
+ __u8 auth_type;
++ __u8 sec_level;
+ __u8 power_save;
+ unsigned long pend;
+
+@@ -325,12 +326,11 @@ int hci_conn_del(struct hci_conn *conn);
+ void hci_conn_hash_flush(struct hci_dev *hdev);
+ void hci_conn_check_pending(struct hci_dev *hdev);
+
+-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 auth_type);
++struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type);
+ int hci_conn_check_link_mode(struct hci_conn *conn);
+-int hci_conn_auth(struct hci_conn *conn);
+-int hci_conn_encrypt(struct hci_conn *conn);
++int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
+ int hci_conn_change_link_key(struct hci_conn *conn);
+-int hci_conn_switch_role(struct hci_conn *conn, uint8_t role);
++int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
+
+ void hci_conn_enter_active_mode(struct hci_conn *conn);
+ void hci_conn_enter_sniff_mode(struct hci_conn *conn);
+@@ -470,26 +470,26 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
+
+ /* ----- HCI protocols ----- */
+ struct hci_proto {
+- char *name;
++ char *name;
+ unsigned int id;
+ unsigned long flags;
+
+ void *priv;
+
+- int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
++ int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
+ int (*connect_cfm) (struct hci_conn *conn, __u8 status);
+- int (*disconn_ind) (struct hci_conn *conn, __u8 reason);
++ int (*disconn_ind) (struct hci_conn *conn);
++ int (*disconn_cfm) (struct hci_conn *conn, __u8 reason);
+ int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+ int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
+- int (*auth_cfm) (struct hci_conn *conn, __u8 status);
+- int (*encrypt_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
++ int (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
+ };
+
+ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
+ {
+ register struct hci_proto *hp;
+ int mask = 0;
+-
++
+ hp = hci_proto[HCI_PROTO_L2CAP];
+ if (hp && hp->connect_ind)
+ mask |= hp->connect_ind(hdev, bdaddr, type);
+@@ -514,30 +514,52 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
+ hp->connect_cfm(conn, status);
+ }
+
+-static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason)
++static inline int hci_proto_disconn_ind(struct hci_conn *conn)
+ {
+ register struct hci_proto *hp;
++ int reason = 0x13;
+
+ hp = hci_proto[HCI_PROTO_L2CAP];
+ if (hp && hp->disconn_ind)
+- hp->disconn_ind(conn, reason);
++ reason = hp->disconn_ind(conn);
+
+ hp = hci_proto[HCI_PROTO_SCO];
+ if (hp && hp->disconn_ind)
+- hp->disconn_ind(conn, reason);
++ reason = hp->disconn_ind(conn);
++
++ return reason;
++}
++
++static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
++{
++ register struct hci_proto *hp;
++
++ hp = hci_proto[HCI_PROTO_L2CAP];
++ if (hp && hp->disconn_cfm)
++ hp->disconn_cfm(conn, reason);
++
++ hp = hci_proto[HCI_PROTO_SCO];
++ if (hp && hp->disconn_cfm)
++ hp->disconn_cfm(conn, reason);
+ }
+
+ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
+ {
+ register struct hci_proto *hp;
++ __u8 encrypt;
++
++ if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
++ return;
++
++ encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
+
+ hp = hci_proto[HCI_PROTO_L2CAP];
+- if (hp && hp->auth_cfm)
+- hp->auth_cfm(conn, status);
++ if (hp && hp->security_cfm)
++ hp->security_cfm(conn, status, encrypt);
+
+ hp = hci_proto[HCI_PROTO_SCO];
+- if (hp && hp->auth_cfm)
+- hp->auth_cfm(conn, status);
++ if (hp && hp->security_cfm)
++ hp->security_cfm(conn, status, encrypt);
+ }
+
+ static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt)
+@@ -545,12 +567,12 @@ static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u
+ register struct hci_proto *hp;
+
+ hp = hci_proto[HCI_PROTO_L2CAP];
+- if (hp && hp->encrypt_cfm)
+- hp->encrypt_cfm(conn, status, encrypt);
++ if (hp && hp->security_cfm)
++ hp->security_cfm(conn, status, encrypt);
+
+ hp = hci_proto[HCI_PROTO_SCO];
+- if (hp && hp->encrypt_cfm)
+- hp->encrypt_cfm(conn, status, encrypt);
++ if (hp && hp->security_cfm)
++ hp->security_cfm(conn, status, encrypt);
+ }
+
+ int hci_register_proto(struct hci_proto *hproto);
+@@ -562,8 +584,7 @@ struct hci_cb {
+
+ char *name;
+
+- void (*auth_cfm) (struct hci_conn *conn, __u8 status);
+- void (*encrypt_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
++ void (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
+ void (*key_change_cfm) (struct hci_conn *conn, __u8 status);
+ void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role);
+ };
+@@ -571,14 +592,20 @@ struct hci_cb {
+ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
+ {
+ struct list_head *p;
++ __u8 encrypt;
+
+ hci_proto_auth_cfm(conn, status);
+
++ if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
++ return;
++
++ encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
++
+ read_lock_bh(&hci_cb_list_lock);
+ list_for_each(p, &hci_cb_list) {
+ struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+- if (cb->auth_cfm)
+- cb->auth_cfm(conn, status);
++ if (cb->security_cfm)
++ cb->security_cfm(conn, status, encrypt);
+ }
+ read_unlock_bh(&hci_cb_list_lock);
+ }
+@@ -587,13 +614,16 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr
+ {
+ struct list_head *p;
+
++ if (conn->sec_level == BT_SECURITY_SDP)
++ conn->sec_level = BT_SECURITY_LOW;
++
+ hci_proto_encrypt_cfm(conn, status, encrypt);
+
+ read_lock_bh(&hci_cb_list_lock);
+ list_for_each(p, &hci_cb_list) {
+ struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+- if (cb->encrypt_cfm)
+- cb->encrypt_cfm(conn, status, encrypt);
++ if (cb->security_cfm)
++ cb->security_cfm(conn, status, encrypt);
+ }
+ read_unlock_bh(&hci_cb_list_lock);
+ }
+diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
+index 73e115b..f566aa1 100644
+--- a/include/net/bluetooth/l2cap.h
++++ b/include/net/bluetooth/l2cap.h
+@@ -37,6 +37,7 @@ struct sockaddr_l2 {
+ sa_family_t l2_family;
+ __le16 l2_psm;
+ bdaddr_t l2_bdaddr;
++ __le16 l2_cid;
+ };
+
+ /* L2CAP socket options */
+@@ -185,6 +186,7 @@ struct l2cap_info_rsp {
+ /* info type */
+ #define L2CAP_IT_CL_MTU 0x0001
+ #define L2CAP_IT_FEAT_MASK 0x0002
++#define L2CAP_IT_FIXED_CHAN 0x0003
+
+ /* info result */
+ #define L2CAP_IR_SUCCESS 0x0000
+@@ -219,11 +221,14 @@ struct l2cap_conn {
+ __u8 rx_ident;
+ __u8 tx_ident;
+
++ __u8 disc_reason;
++
+ struct l2cap_chan_list chan_list;
+ };
+
+ #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
+-#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x02
++#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04
++#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08
+
+ /* ----- L2CAP channel and socket info ----- */
+ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
+@@ -237,8 +242,9 @@ struct l2cap_pinfo {
+ __u16 imtu;
+ __u16 omtu;
+ __u16 flush_to;
+-
+- __u32 link_mode;
++ __u8 sec_level;
++ __u8 role_switch;
++ __u8 force_reliable;
+
+ __u8 conf_req[64];
+ __u8 conf_len;
+@@ -257,6 +263,7 @@ struct l2cap_pinfo {
+ #define L2CAP_CONF_REQ_SENT 0x01
+ #define L2CAP_CONF_INPUT_DONE 0x02
+ #define L2CAP_CONF_OUTPUT_DONE 0x04
++#define L2CAP_CONF_CONNECT_PEND 0x80
+
+ #define L2CAP_CONF_MAX_RETRIES 2
+
+diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
+index 4dc8d92..8007261 100644
+--- a/include/net/bluetooth/rfcomm.h
++++ b/include/net/bluetooth/rfcomm.h
+@@ -183,8 +183,9 @@ struct rfcomm_dlc {
+ u8 remote_v24_sig;
+ u8 mscex;
+ u8 out;
+-
+- u32 link_mode;
++ u8 sec_level;
++ u8 role_switch;
++ u32 defer_setup;
+
+ uint mtu;
+ uint cfc;
+@@ -202,10 +203,12 @@ struct rfcomm_dlc {
+ #define RFCOMM_RX_THROTTLED 0
+ #define RFCOMM_TX_THROTTLED 1
+ #define RFCOMM_TIMED_OUT 2
+-#define RFCOMM_MSC_PENDING 3
+-#define RFCOMM_AUTH_PENDING 4
+-#define RFCOMM_AUTH_ACCEPT 5
+-#define RFCOMM_AUTH_REJECT 6
++#define RFCOMM_MSC_PENDING 3
++#define RFCOMM_SEC_PENDING 4
++#define RFCOMM_AUTH_PENDING 5
++#define RFCOMM_AUTH_ACCEPT 6
++#define RFCOMM_AUTH_REJECT 7
++#define RFCOMM_DEFER_SETUP 8
+
+ /* Scheduling flags and events */
+ #define RFCOMM_SCHED_STATE 0
+@@ -239,6 +242,7 @@ int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
+ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
+ int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
+ int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
++void rfcomm_dlc_accept(struct rfcomm_dlc *d);
+
+ #define rfcomm_dlc_lock(d) spin_lock(&d->lock)
+ #define rfcomm_dlc_unlock(d) spin_unlock(&d->lock)
+@@ -304,7 +308,8 @@ struct rfcomm_pinfo {
+ struct bt_sock bt;
+ struct rfcomm_dlc *dlc;
+ u8 channel;
+- u32 link_mode;
++ u8 sec_level;
++ u8 role_switch;
+ };
+
+ int rfcomm_init_sockets(void);
+@@ -333,7 +338,6 @@ struct rfcomm_dev_req {
+ bdaddr_t src;
+ bdaddr_t dst;
+ u8 channel;
+-
+ };
+
+ struct rfcomm_dev_info {
+diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
+index 744ed3f..02b9baa 100644
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -41,14 +41,13 @@
+
+ #include <net/bluetooth/bluetooth.h>
+
+-#define VERSION "2.14"
++#define VERSION "2.15"
+
+ /* Bluetooth sockets */
+ #define BT_MAX_PROTO 8
+ static struct net_proto_family *bt_proto[BT_MAX_PROTO];
+ static DEFINE_RWLOCK(bt_proto_lock);
+
+-#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
+ static const char *bt_key_strings[BT_MAX_PROTO] = {
+ "sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP",
+@@ -86,11 +85,6 @@ static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
+ bt_slock_key_strings[proto], &bt_slock_key[proto],
+ bt_key_strings[proto], &bt_lock_key[proto]);
+ }
+-#else
+-static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
+-{
+-}
+-#endif
+
+ int bt_sock_register(int proto, struct net_proto_family *ops)
+ {
+@@ -217,7 +211,8 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
+ continue;
+ }
+
+- if (sk->sk_state == BT_CONNECTED || !newsock) {
++ if (sk->sk_state == BT_CONNECTED || !newsock ||
++ bt_sk(parent)->defer_setup) {
+ bt_accept_unlink(sk);
+ if (newsock)
+ sock_graft(sk, newsock);
+@@ -232,7 +227,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
+ EXPORT_SYMBOL(bt_accept_dequeue);
+
+ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+- struct msghdr *msg, size_t len, int flags)
++ struct msghdr *msg, size_t len, int flags)
+ {
+ int noblock = flags & MSG_DONTWAIT;
+ struct sock *sk = sock->sk;
+@@ -277,7 +272,9 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
+
+ list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
+ sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
+- if (sk->sk_state == BT_CONNECTED)
++ if (sk->sk_state == BT_CONNECTED ||
++ (bt_sk(parent)->defer_setup &&
++ sk->sk_state == BT_CONNECT2))
+ return POLLIN | POLLRDNORM;
+ }
+
+diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
+index c9cac77..0073ec8 100644
+--- a/net/bluetooth/cmtp/core.c
++++ b/net/bluetooth/cmtp/core.c
+@@ -126,8 +126,7 @@ static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const
+
+ session->reassembly[id] = nskb;
+
+- if (skb)
+- kfree_skb(skb);
++ kfree_skb(skb);
+ }
+
+ static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
+diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
+index a4a789f..1181db0 100644
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -123,6 +123,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
+ conn->state = BT_CONNECT;
+ conn->out = 1;
+
++ conn->attempt++;
++
+ cp.handle = cpu_to_le16(handle);
+ cp.pkt_type = cpu_to_le16(conn->pkt_type);
+
+@@ -139,6 +141,8 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
+ conn->state = BT_CONNECT;
+ conn->out = 1;
+
++ conn->attempt++;
++
+ cp.handle = cpu_to_le16(handle);
+ cp.pkt_type = cpu_to_le16(conn->pkt_type);
+
+@@ -155,6 +159,7 @@ static void hci_conn_timeout(unsigned long arg)
+ {
+ struct hci_conn *conn = (void *) arg;
+ struct hci_dev *hdev = conn->hdev;
++ __u8 reason;
+
+ BT_DBG("conn %p state %d", conn, conn->state);
+
+@@ -173,7 +178,8 @@ static void hci_conn_timeout(unsigned long arg)
+ break;
+ case BT_CONFIG:
+ case BT_CONNECTED:
+- hci_acl_disconn(conn, 0x13);
++ reason = hci_proto_disconn_ind(conn);
++ hci_acl_disconn(conn, reason);
+ break;
+ default:
+ conn->state = BT_CLOSED;
+@@ -216,12 +222,13 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
+ break;
+ case SCO_LINK:
+ if (lmp_esco_capable(hdev))
+- conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK;
++ conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
++ (hdev->esco_type & EDR_ESCO_MASK);
+ else
+ conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
+ break;
+ case ESCO_LINK:
+- conn->pkt_type = hdev->esco_type;
++ conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
+ break;
+ }
+
+@@ -280,6 +287,8 @@ int hci_conn_del(struct hci_conn *conn)
+
+ skb_queue_purge(&conn->data_q);
+
++ hci_conn_del_sysfs(conn);
++
+ return 0;
+ }
+
+@@ -325,7 +334,7 @@ EXPORT_SYMBOL(hci_get_route);
+
+ /* Create SCO or ACL connection.
+ * Device _must_ be locked */
+-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 auth_type)
++struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
+ {
+ struct hci_conn *acl;
+ struct hci_conn *sco;
+@@ -340,6 +349,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
+ hci_conn_hold(acl);
+
+ if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
++ acl->sec_level = sec_level;
+ acl->auth_type = auth_type;
+ hci_acl_connect(acl);
+ }
+@@ -385,51 +395,59 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
+ EXPORT_SYMBOL(hci_conn_check_link_mode);
+
+ /* Authenticate remote device */
+-int hci_conn_auth(struct hci_conn *conn)
++static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
+ {
+ BT_DBG("conn %p", conn);
+
+- if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) {
+- if (!(conn->auth_type & 0x01)) {
+- conn->auth_type |= 0x01;
+- conn->link_mode &= ~HCI_LM_AUTH;
+- }
+- }
+-
+- if (conn->link_mode & HCI_LM_AUTH)
++ if (sec_level > conn->sec_level)
++ conn->sec_level = sec_level;
++ else if (conn->link_mode & HCI_LM_AUTH)
+ return 1;
+
++ conn->auth_type = auth_type;
++
+ if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
+ struct hci_cp_auth_requested cp;
+ cp.handle = cpu_to_le16(conn->handle);
+ hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
+ sizeof(cp), &cp);
+ }
++
+ return 0;
+ }
+-EXPORT_SYMBOL(hci_conn_auth);
+
+-/* Enable encryption */
+-int hci_conn_encrypt(struct hci_conn *conn)
++/* Enable security */
++int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
+ {
+ BT_DBG("conn %p", conn);
+
++ if (sec_level == BT_SECURITY_SDP)
++ return 1;
++
++ if (sec_level == BT_SECURITY_LOW) {
++ if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0)
++ return hci_conn_auth(conn, sec_level, auth_type);
++ else
++ return 1;
++ }
++
+ if (conn->link_mode & HCI_LM_ENCRYPT)
+- return hci_conn_auth(conn);
++ return hci_conn_auth(conn, sec_level, auth_type);
+
+ if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+ return 0;
+
+- if (hci_conn_auth(conn)) {
++ 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);
+ }
++
+ return 0;
+ }
+-EXPORT_SYMBOL(hci_conn_encrypt);
++EXPORT_SYMBOL(hci_conn_security);
+
+ /* Change link key */
+ int hci_conn_change_link_key(struct hci_conn *conn)
+@@ -442,12 +460,13 @@ int hci_conn_change_link_key(struct hci_conn *conn)
+ hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
+ sizeof(cp), &cp);
+ }
++
+ return 0;
+ }
+ EXPORT_SYMBOL(hci_conn_change_link_key);
+
+ /* Switch role */
+-int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
++int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
+ {
+ BT_DBG("conn %p", conn);
+
+@@ -460,6 +479,7 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
+ cp.role = role;
+ hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
+ }
++
+ return 0;
+ }
+ EXPORT_SYMBOL(hci_conn_switch_role);
+@@ -542,9 +562,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
+
+ c->state = BT_CLOSED;
+
+- hci_conn_del_sysfs(c);
+-
+- hci_proto_disconn_ind(c, 0x16);
++ hci_proto_disconn_cfm(c, 0x16);
+ hci_conn_del(c);
+ }
+ }
+diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
+index ba78cc1..cd06151 100644
+--- a/net/bluetooth/hci_core.c
++++ b/net/bluetooth/hci_core.c
+@@ -1565,8 +1565,7 @@ static void hci_cmd_task(unsigned long arg)
+
+ /* Send queued commands */
+ if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
+- if (hdev->sent_cmd)
+- kfree_skb(hdev->sent_cmd);
++ kfree_skb(hdev->sent_cmd);
+
+ if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
+ atomic_dec(&hdev->cmd_cnt);
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index f91ba69..5553424 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -484,6 +484,15 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
+ if (hdev->features[4] & LMP_EV5)
+ hdev->esco_type |= (ESCO_EV5);
+
++ if (hdev->features[5] & LMP_EDR_ESCO_2M)
++ hdev->esco_type |= (ESCO_2EV3);
++
++ if (hdev->features[5] & LMP_EDR_ESCO_3M)
++ hdev->esco_type |= (ESCO_3EV3);
++
++ if (hdev->features[5] & LMP_EDR_3S_ESCO)
++ hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
++
+ BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
+ hdev->features[0], hdev->features[1],
+ hdev->features[2], hdev->features[3],
+@@ -914,7 +923,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
+ if (ev->status) {
+ hci_proto_connect_cfm(conn, ev->status);
+ hci_conn_del(conn);
+- }
++ } else if (ev->link_type != ACL_LINK)
++ hci_proto_connect_cfm(conn, ev->status);
+
+ unlock:
+ hci_dev_unlock(hdev);
+@@ -1009,9 +1019,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
+ if (conn) {
+ conn->state = BT_CLOSED;
+
+- hci_conn_del_sysfs(conn);
+-
+- hci_proto_disconn_ind(conn, ev->reason);
++ hci_proto_disconn_cfm(conn, ev->reason);
+ hci_conn_del(conn);
+ }
+
+@@ -1600,7 +1608,8 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
+
+ if (conn->state == BT_CONFIG) {
+ if (!ev->status && hdev->ssp_mode > 0 &&
+- conn->ssp_mode > 0 && conn->out) {
++ conn->ssp_mode > 0 && conn->out &&
++ conn->sec_level != BT_SECURITY_SDP) {
+ struct hci_cp_auth_requested cp;
+ cp.handle = ev->handle;
+ hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
+@@ -1637,6 +1646,13 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
+ conn->type = SCO_LINK;
+ }
+
++ if (conn->out && ev->status == 0x1c && conn->attempt < 2) {
++ conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
++ (hdev->esco_type & EDR_ESCO_MASK);
++ hci_setup_sync(conn, conn->link->handle);
++ goto unlock;
++ }
++
+ if (!ev->status) {
+ conn->handle = __le16_to_cpu(ev->handle);
+ conn->state = BT_CONNECTED;
+diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
+index b93748e..ca4d3b4 100644
+--- a/net/bluetooth/l2cap.c
++++ b/net/bluetooth/l2cap.c
+@@ -50,9 +50,10 @@
+ #include <net/bluetooth/hci_core.h>
+ #include <net/bluetooth/l2cap.h>
+
+-#define VERSION "2.11"
++#define VERSION "2.13"
+
+-static u32 l2cap_feat_mask = 0x0000;
++static u32 l2cap_feat_mask = 0x0080;
++static u8 l2cap_fixed_chan[8] = { 0x02, };
+
+ static const struct proto_ops l2cap_sock_ops;
+
+@@ -77,9 +78,10 @@ static void l2cap_sock_timeout(unsigned long arg)
+
+ bh_lock_sock(sk);
+
+- if (sk->sk_state == BT_CONNECT &&
+- (l2cap_pi(sk)->link_mode & (L2CAP_LM_AUTH |
+- L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)))
++ if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
++ reason = ECONNREFUSED;
++ else if (sk->sk_state == BT_CONNECT &&
++ l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
+ reason = ECONNREFUSED;
+ else
+ reason = ETIMEDOUT;
+@@ -204,6 +206,8 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
+
+ BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+
++ conn->disc_reason = 0x13;
++
+ l2cap_pi(sk)->conn = conn;
+
+ if (sk->sk_type == SOCK_SEQPACKET) {
+@@ -259,18 +263,35 @@ static void l2cap_chan_del(struct sock *sk, int err)
+ }
+
+ /* Service level security */
+-static inline int l2cap_check_link_mode(struct sock *sk)
++static inline int l2cap_check_security(struct sock *sk)
+ {
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
++ __u8 auth_type;
+
+- if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) ||
+- (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE))
+- return hci_conn_encrypt(conn->hcon);
++ if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
++ if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
++ auth_type = HCI_AT_NO_BONDING_MITM;
++ else
++ auth_type = HCI_AT_NO_BONDING;
+
+- if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH)
+- return hci_conn_auth(conn->hcon);
++ if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
++ l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
++ } else {
++ switch (l2cap_pi(sk)->sec_level) {
++ case BT_SECURITY_HIGH:
++ auth_type = HCI_AT_GENERAL_BONDING_MITM;
++ break;
++ case BT_SECURITY_MEDIUM:
++ auth_type = HCI_AT_GENERAL_BONDING;
++ break;
++ default:
++ auth_type = HCI_AT_NO_BONDING;
++ break;
++ }
++ }
+
+- return 1;
++ return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
++ auth_type);
+ }
+
+ static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
+@@ -312,7 +333,10 @@ static void l2cap_do_start(struct sock *sk)
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+
+ if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
+- if (l2cap_check_link_mode(sk)) {
++ if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
++ return;
++
++ if (l2cap_check_security(sk)) {
+ struct l2cap_conn_req req;
+ req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+ req.psm = l2cap_pi(sk)->psm;
+@@ -356,7 +380,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
+ }
+
+ if (sk->sk_state == BT_CONNECT) {
+- if (l2cap_check_link_mode(sk)) {
++ if (l2cap_check_security(sk)) {
+ struct l2cap_conn_req req;
+ req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+ req.psm = l2cap_pi(sk)->psm;
+@@ -371,10 +395,18 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
+ rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
+ rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
+
+- if (l2cap_check_link_mode(sk)) {
+- sk->sk_state = BT_CONFIG;
+- rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
+- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
++ if (l2cap_check_security(sk)) {
++ if (bt_sk(sk)->defer_setup) {
++ struct sock *parent = bt_sk(sk)->parent;
++ rsp.result = cpu_to_le16(L2CAP_CR_PEND);
++ rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
++ parent->sk_data_ready(parent, 0);
++
++ } else {
++ sk->sk_state = BT_CONFIG;
++ rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
++ rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
++ }
+ } else {
+ rsp.result = cpu_to_le16(L2CAP_CR_PEND);
+ rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
+@@ -426,7 +458,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
+ read_lock(&l->lock);
+
+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+- if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
++ if (l2cap_pi(sk)->force_reliable)
+ sk->sk_err = err;
+ }
+
+@@ -437,6 +469,7 @@ static void l2cap_info_timeout(unsigned long arg)
+ {
+ struct l2cap_conn *conn = (void *) arg;
+
++ conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
+ conn->info_ident = 0;
+
+ l2cap_conn_start(conn);
+@@ -470,6 +503,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
+ spin_lock_init(&conn->lock);
+ rwlock_init(&conn->chan_list.lock);
+
++ conn->disc_reason = 0x13;
++
+ return conn;
+ }
+
+@@ -483,8 +518,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
+
+ BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
+
+- if (conn->rx_skb)
+- kfree_skb(conn->rx_skb);
++ kfree_skb(conn->rx_skb);
+
+ /* Kill channels */
+ while ((sk = conn->chan_list.head)) {
+@@ -608,7 +642,6 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
+
+ case BT_CONNECTED:
+ case BT_CONFIG:
+- case BT_CONNECT2:
+ if (sk->sk_type == SOCK_SEQPACKET) {
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+ struct l2cap_disconn_req req;
+@@ -624,6 +657,27 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
+ l2cap_chan_del(sk, reason);
+ break;
+
++ case BT_CONNECT2:
++ if (sk->sk_type == SOCK_SEQPACKET) {
++ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
++ struct l2cap_conn_rsp rsp;
++ __u16 result;
++
++ if (bt_sk(sk)->defer_setup)
++ result = L2CAP_CR_SEC_BLOCK;
++ else
++ result = L2CAP_CR_BAD_PSM;
++
++ rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
++ rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
++ rsp.result = cpu_to_le16(result);
++ rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
++ l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
++ L2CAP_CONN_RSP, sizeof(rsp), &rsp);
++ } else
++ l2cap_chan_del(sk, reason);
++ break;
++
+ case BT_CONNECT:
+ case BT_DISCONN:
+ l2cap_chan_del(sk, reason);
+@@ -653,13 +707,19 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
+
+ if (parent) {
+ sk->sk_type = parent->sk_type;
++ bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
++
+ pi->imtu = l2cap_pi(parent)->imtu;
+ pi->omtu = l2cap_pi(parent)->omtu;
+- pi->link_mode = l2cap_pi(parent)->link_mode;
++ pi->sec_level = l2cap_pi(parent)->sec_level;
++ pi->role_switch = l2cap_pi(parent)->role_switch;
++ pi->force_reliable = l2cap_pi(parent)->force_reliable;
+ } else {
+ pi->imtu = L2CAP_DEFAULT_MTU;
+ pi->omtu = 0;
+- pi->link_mode = 0;
++ pi->sec_level = BT_SECURITY_LOW;
++ pi->role_switch = 0;
++ pi->force_reliable = 0;
+ }
+
+ /* Default config options */
+@@ -723,17 +783,24 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol)
+ return 0;
+ }
+
+-static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
++static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
+ {
+- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+ struct sock *sk = sock->sk;
+- int err = 0;
++ struct sockaddr_l2 la;
++ int len, err = 0;
+
+- BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
++ BT_DBG("sk %p", sk);
+
+ if (!addr || addr->sa_family != AF_BLUETOOTH)
+ return -EINVAL;
+
++ memset(&la, 0, sizeof(la));
++ len = min_t(unsigned int, sizeof(la), alen);
++ memcpy(&la, addr, len);
++
++ if (la.l2_cid)
++ return -EINVAL;
++
+ lock_sock(sk);
+
+ if (sk->sk_state != BT_OPEN) {
+@@ -741,7 +808,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_
+ goto done;
+ }
+
+- if (la->l2_psm && btohs(la->l2_psm) < 0x1001 &&
++ if (la.l2_psm && btohs(la.l2_psm) < 0x1001 &&
+ !capable(CAP_NET_BIND_SERVICE)) {
+ err = -EACCES;
+ goto done;
+@@ -749,14 +816,17 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_
+
+ write_lock_bh(&l2cap_sk_list.lock);
+
+- if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
++ if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
+ err = -EADDRINUSE;
+ } else {
+ /* Save source address */
+- bacpy(&bt_sk(sk)->src, &la->l2_bdaddr);
+- l2cap_pi(sk)->psm = la->l2_psm;
+- l2cap_pi(sk)->sport = la->l2_psm;
++ bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
++ l2cap_pi(sk)->psm = la.l2_psm;
++ l2cap_pi(sk)->sport = la.l2_psm;
+ sk->sk_state = BT_BOUND;
++
++ if (btohs(la.l2_psm) == 0x0001 || btohs(la.l2_psm) == 0x0003)
++ l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+ }
+
+ write_unlock_bh(&l2cap_sk_list.lock);
+@@ -776,7 +846,8 @@ static int l2cap_do_connect(struct sock *sk)
+ __u8 auth_type;
+ int err = 0;
+
+- BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
++ BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
++ l2cap_pi(sk)->psm);
+
+ if (!(hdev = hci_get_route(dst, src)))
+ return -EHOSTUNREACH;
+@@ -785,21 +856,42 @@ static int l2cap_do_connect(struct sock *sk)
+
+ err = -ENOMEM;
+
+- if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH ||
+- l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT ||
+- l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
+- if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
++ if (sk->sk_type == SOCK_RAW) {
++ switch (l2cap_pi(sk)->sec_level) {
++ case BT_SECURITY_HIGH:
++ auth_type = HCI_AT_DEDICATED_BONDING_MITM;
++ break;
++ case BT_SECURITY_MEDIUM:
++ auth_type = HCI_AT_DEDICATED_BONDING;
++ break;
++ default:
++ auth_type = HCI_AT_NO_BONDING;
++ break;
++ }
++ } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
++ if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+ auth_type = HCI_AT_NO_BONDING_MITM;
+ else
+- auth_type = HCI_AT_GENERAL_BONDING_MITM;
+- } else {
+- if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
+ auth_type = HCI_AT_NO_BONDING;
+- else
++
++ if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
++ l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
++ } else {
++ switch (l2cap_pi(sk)->sec_level) {
++ case BT_SECURITY_HIGH:
++ auth_type = HCI_AT_GENERAL_BONDING_MITM;
++ break;
++ case BT_SECURITY_MEDIUM:
+ auth_type = HCI_AT_GENERAL_BONDING;
++ break;
++ default:
++ auth_type = HCI_AT_NO_BONDING;
++ break;
++ }
+ }
+
+- hcon = hci_connect(hdev, ACL_LINK, dst, auth_type);
++ hcon = hci_connect(hdev, ACL_LINK, dst,
++ l2cap_pi(sk)->sec_level, auth_type);
+ if (!hcon)
+ goto done;
+
+@@ -835,20 +927,25 @@ done:
+
+ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+ {
+- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+ struct sock *sk = sock->sk;
+- int err = 0;
+-
+- lock_sock(sk);
++ struct sockaddr_l2 la;
++ int len, err = 0;
+
+ BT_DBG("sk %p", sk);
+
+- if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
+- err = -EINVAL;
+- goto done;
+- }
++ if (!addr || addr->sa_family != AF_BLUETOOTH)
++ return -EINVAL;
++
++ memset(&la, 0, sizeof(la));
++ len = min_t(unsigned int, sizeof(la), alen);
++ memcpy(&la, addr, len);
++
++ if (la.l2_cid)
++ return -EINVAL;
++
++ lock_sock(sk);
+
+- if (sk->sk_type == SOCK_SEQPACKET && !la->l2_psm) {
++ if (sk->sk_type == SOCK_SEQPACKET && !la.l2_psm) {
+ err = -EINVAL;
+ goto done;
+ }
+@@ -875,8 +972,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
+ }
+
+ /* Set destination address and psm */
+- bacpy(&bt_sk(sk)->dst, &la->l2_bdaddr);
+- l2cap_pi(sk)->psm = la->l2_psm;
++ bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
++ l2cap_pi(sk)->psm = la.l2_psm;
+
+ if ((err = l2cap_do_connect(sk)))
+ goto done;
+@@ -1000,12 +1097,16 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
+ addr->sa_family = AF_BLUETOOTH;
+ *len = sizeof(struct sockaddr_l2);
+
+- if (peer)
++ if (peer) {
++ la->l2_psm = l2cap_pi(sk)->psm;
+ bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
+- else
++ la->l2_cid = htobs(l2cap_pi(sk)->dcid);
++ } else {
++ la->l2_psm = l2cap_pi(sk)->sport;
+ bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
++ la->l2_cid = htobs(l2cap_pi(sk)->scid);
++ }
+
+- la->l2_psm = l2cap_pi(sk)->psm;
+ return 0;
+ }
+
+@@ -1106,11 +1207,38 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
+ return err;
+ }
+
+-static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
++static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
++{
++ struct sock *sk = sock->sk;
++
++ lock_sock(sk);
++
++ if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
++ struct l2cap_conn_rsp rsp;
++
++ sk->sk_state = BT_CONFIG;
++
++ rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
++ rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
++ rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
++ rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
++ l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
++ L2CAP_CONN_RSP, sizeof(rsp), &rsp);
++
++ release_sock(sk);
++ return 0;
++ }
++
++ release_sock(sk);
++
++ return bt_sock_recvmsg(iocb, sock, msg, len, flags);
++}
++
++static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen)
+ {
+ struct sock *sk = sock->sk;
+ struct l2cap_options opts;
+- int err = 0, len;
++ int len, err = 0;
+ u32 opt;
+
+ BT_DBG("sk %p", sk);
+@@ -1140,7 +1268,15 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
+ break;
+ }
+
+- l2cap_pi(sk)->link_mode = opt;
++ if (opt & L2CAP_LM_AUTH)
++ l2cap_pi(sk)->sec_level = BT_SECURITY_LOW;
++ if (opt & L2CAP_LM_ENCRYPT)
++ l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
++ if (opt & L2CAP_LM_SECURE)
++ l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH;
++
++ l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER);
++ l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE);
+ break;
+
+ default:
+@@ -1152,12 +1288,77 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
+ return err;
+ }
+
+-static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
++static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
++{
++ struct sock *sk = sock->sk;
++ struct bt_security sec;
++ int len, err = 0;
++ u32 opt;
++
++ BT_DBG("sk %p", sk);
++
++ if (level == SOL_L2CAP)
++ return l2cap_sock_setsockopt_old(sock, optname, optval, optlen);
++
++ if (level != SOL_BLUETOOTH)
++ return -ENOPROTOOPT;
++
++ lock_sock(sk);
++
++ switch (optname) {
++ case BT_SECURITY:
++ if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
++ err = -EINVAL;
++ break;
++ }
++
++ sec.level = BT_SECURITY_LOW;
++
++ len = min_t(unsigned int, sizeof(sec), optlen);
++ if (copy_from_user((char *) &sec, optval, len)) {
++ err = -EFAULT;
++ break;
++ }
++
++ if (sec.level < BT_SECURITY_LOW ||
++ sec.level > BT_SECURITY_HIGH) {
++ err = -EINVAL;
++ break;
++ }
++
++ l2cap_pi(sk)->sec_level = sec.level;
++ break;
++
++ case BT_DEFER_SETUP:
++ if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
++ err = -EINVAL;
++ break;
++ }
++
++ if (get_user(opt, (u32 __user *) optval)) {
++ err = -EFAULT;
++ break;
++ }
++
++ bt_sk(sk)->defer_setup = opt;
++ break;
++
++ default:
++ err = -ENOPROTOOPT;
++ break;
++ }
++
++ release_sock(sk);
++ return err;
++}
++
++static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
+ {
+ struct sock *sk = sock->sk;
+ struct l2cap_options opts;
+ struct l2cap_conninfo cinfo;
+ int len, err = 0;
++ u32 opt;
+
+ BT_DBG("sk %p", sk);
+
+@@ -1180,12 +1381,36 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
+ break;
+
+ case L2CAP_LM:
+- if (put_user(l2cap_pi(sk)->link_mode, (u32 __user *) optval))
++ switch (l2cap_pi(sk)->sec_level) {
++ case BT_SECURITY_LOW:
++ opt = L2CAP_LM_AUTH;
++ break;
++ case BT_SECURITY_MEDIUM:
++ opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;
++ break;
++ case BT_SECURITY_HIGH:
++ opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
++ L2CAP_LM_SECURE;
++ break;
++ default:
++ opt = 0;
++ break;
++ }
++
++ if (l2cap_pi(sk)->role_switch)
++ opt |= L2CAP_LM_MASTER;
++
++ if (l2cap_pi(sk)->force_reliable)
++ opt |= L2CAP_LM_RELIABLE;
++
++ if (put_user(opt, (u32 __user *) optval))
+ err = -EFAULT;
+ break;
+
+ case L2CAP_CONNINFO:
+- if (sk->sk_state != BT_CONNECTED) {
++ if (sk->sk_state != BT_CONNECTED &&
++ !(sk->sk_state == BT_CONNECT2 &&
++ bt_sk(sk)->defer_setup)) {
+ err = -ENOTCONN;
+ break;
+ }
+@@ -1208,6 +1433,60 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
+ return err;
+ }
+
++static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
++{
++ struct sock *sk = sock->sk;
++ struct bt_security sec;
++ int len, err = 0;
++
++ BT_DBG("sk %p", sk);
++
++ if (level == SOL_L2CAP)
++ return l2cap_sock_getsockopt_old(sock, optname, optval, optlen);
++
++ if (level != SOL_BLUETOOTH)
++ return -ENOPROTOOPT;
++
++ if (get_user(len, optlen))
++ return -EFAULT;
++
++ lock_sock(sk);
++
++ switch (optname) {
++ case BT_SECURITY:
++ if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
++ err = -EINVAL;
++ break;
++ }
++
++ sec.level = l2cap_pi(sk)->sec_level;
++
++ len = min_t(unsigned int, len, sizeof(sec));
++ if (copy_to_user(optval, (char *) &sec, len))
++ err = -EFAULT;
++
++ break;
++
++ case BT_DEFER_SETUP:
++ if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
++ err = -EINVAL;
++ break;
++ }
++
++ if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
++ err = -EFAULT;
++
++ break;
++
++ default:
++ err = -ENOPROTOOPT;
++ break;
++ }
++
++ release_sock(sk);
++ return err;
++}
++
+ static int l2cap_sock_shutdown(struct socket *sock, int how)
+ {
+ struct sock *sk = sock->sk;
+@@ -1270,11 +1549,6 @@ static void l2cap_chan_ready(struct sock *sk)
+ */
+ parent->sk_data_ready(parent, 0);
+ }
+-
+- if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
+- struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+- hci_conn_change_link_key(conn->hcon);
+- }
+ }
+
+ /* Copy frame to all raw sockets on that connection */
+@@ -1549,8 +1823,11 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
+
+ if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
+ cmd->ident == conn->info_ident) {
+- conn->info_ident = 0;
+ del_timer(&conn->info_timer);
++
++ conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
++ conn->info_ident = 0;
++
+ l2cap_conn_start(conn);
+ }
+
+@@ -1580,6 +1857,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
+ /* Check if the ACL is secure enough (if not SDP) */
+ if (psm != cpu_to_le16(0x0001) &&
+ !hci_conn_check_link_mode(conn->hcon)) {
++ conn->disc_reason = 0x05;
+ result = L2CAP_CR_SEC_BLOCK;
+ goto response;
+ }
+@@ -1621,11 +1899,18 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
+
+ l2cap_pi(sk)->ident = cmd->ident;
+
+- if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
+- if (l2cap_check_link_mode(sk)) {
+- sk->sk_state = BT_CONFIG;
+- result = L2CAP_CR_SUCCESS;
+- status = L2CAP_CS_NO_INFO;
++ if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
++ if (l2cap_check_security(sk)) {
++ if (bt_sk(sk)->defer_setup) {
++ sk->sk_state = BT_CONNECT2;
++ result = L2CAP_CR_PEND;
++ status = L2CAP_CS_AUTHOR_PEND;
++ parent->sk_data_ready(parent, 0);
++ } else {
++ sk->sk_state = BT_CONFIG;
++ result = L2CAP_CR_SUCCESS;
++ status = L2CAP_CS_NO_INFO;
++ }
+ } else {
+ sk->sk_state = BT_CONNECT2;
+ result = L2CAP_CR_PEND;
+@@ -1695,11 +1980,14 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
+ l2cap_pi(sk)->dcid = dcid;
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+
++ l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
++
+ l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
+ l2cap_build_conf_req(sk, req), req);
+ break;
+
+ case L2CAP_CR_PEND:
++ l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
+ break;
+
+ default:
+@@ -1908,6 +2196,14 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
+ put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data);
+ l2cap_send_cmd(conn, cmd->ident,
+ L2CAP_INFO_RSP, sizeof(buf), buf);
++ } else if (type == L2CAP_IT_FIXED_CHAN) {
++ u8 buf[12];
++ struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
++ rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
++ rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
++ memcpy(buf + 4, l2cap_fixed_chan, 8);
++ l2cap_send_cmd(conn, cmd->ident,
++ L2CAP_INFO_RSP, sizeof(buf), buf);
+ } else {
+ struct l2cap_info_rsp rsp;
+ rsp.type = cpu_to_le16(type);
+@@ -1929,14 +2225,31 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
+
+ BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
+
+- conn->info_ident = 0;
+-
+ del_timer(&conn->info_timer);
+
+- if (type == L2CAP_IT_FEAT_MASK)
++ if (type == L2CAP_IT_FEAT_MASK) {
+ conn->feat_mask = get_unaligned_le32(rsp->data);
+
+- l2cap_conn_start(conn);
++ if (conn->feat_mask & 0x0080) {
++ struct l2cap_info_req req;
++ req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
++
++ conn->info_ident = l2cap_get_ident(conn);
++
++ l2cap_send_cmd(conn, conn->info_ident,
++ L2CAP_INFO_REQ, sizeof(req), &req);
++ } else {
++ conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
++ conn->info_ident = 0;
++
++ l2cap_conn_start(conn);
++ }
++ } else if (type == L2CAP_IT_FIXED_CHAN) {
++ conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
++ conn->info_ident = 0;
++
++ l2cap_conn_start(conn);
++ }
+
+ return 0;
+ }
+@@ -2143,10 +2456,15 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
+ continue;
+
+ if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
+- lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
++ lm1 |= HCI_LM_ACCEPT;
++ if (l2cap_pi(sk)->role_switch)
++ lm1 |= HCI_LM_MASTER;
+ exact++;
+- } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
+- lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
++ } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
++ lm2 |= HCI_LM_ACCEPT;
++ if (l2cap_pi(sk)->role_switch)
++ lm2 |= HCI_LM_MASTER;
++ }
+ }
+ read_unlock(&l2cap_sk_list.lock);
+
+@@ -2172,89 +2490,48 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
+ return 0;
+ }
+
+-static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
++static int l2cap_disconn_ind(struct hci_conn *hcon)
+ {
+- BT_DBG("hcon %p reason %d", hcon, reason);
++ struct l2cap_conn *conn = hcon->l2cap_data;
+
+- if (hcon->type != ACL_LINK)
+- return 0;
++ BT_DBG("hcon %p", hcon);
+
+- l2cap_conn_del(hcon, bt_err(reason));
++ if (hcon->type != ACL_LINK || !conn)
++ return 0x13;
+
+- return 0;
++ return conn->disc_reason;
+ }
+
+-static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
++static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
+ {
+- struct l2cap_chan_list *l;
+- struct l2cap_conn *conn = hcon->l2cap_data;
+- struct sock *sk;
++ BT_DBG("hcon %p reason %d", hcon, reason);
+
+- if (!conn)
++ if (hcon->type != ACL_LINK)
+ return 0;
+
+- l = &conn->chan_list;
+-
+- BT_DBG("conn %p", conn);
+-
+- read_lock(&l->lock);
+-
+- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+- struct l2cap_pinfo *pi = l2cap_pi(sk);
+-
+- bh_lock_sock(sk);
+-
+- if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
+- !(hcon->link_mode & HCI_LM_ENCRYPT) &&
+- !status) {
+- bh_unlock_sock(sk);
+- continue;
+- }
+-
+- if (sk->sk_state == BT_CONNECT) {
+- if (!status) {
+- struct l2cap_conn_req req;
+- req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+- req.psm = l2cap_pi(sk)->psm;
+-
+- l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+-
+- l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+- L2CAP_CONN_REQ, sizeof(req), &req);
+- } else {
+- l2cap_sock_clear_timer(sk);
+- l2cap_sock_set_timer(sk, HZ / 10);
+- }
+- } else if (sk->sk_state == BT_CONNECT2) {
+- struct l2cap_conn_rsp rsp;
+- __u16 result;
++ l2cap_conn_del(hcon, bt_err(reason));
+
+- if (!status) {
+- sk->sk_state = BT_CONFIG;
+- result = L2CAP_CR_SUCCESS;
+- } else {
+- sk->sk_state = BT_DISCONN;
+- l2cap_sock_set_timer(sk, HZ / 10);
+- result = L2CAP_CR_SEC_BLOCK;
+- }
++ return 0;
++}
+
+- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
+- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
+- rsp.result = cpu_to_le16(result);
+- rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+- l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+- L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+- }
++static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt)
++{
++ if (sk->sk_type != SOCK_SEQPACKET)
++ return;
+
+- bh_unlock_sock(sk);
++ if (encrypt == 0x00) {
++ if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
++ l2cap_sock_clear_timer(sk);
++ l2cap_sock_set_timer(sk, HZ * 5);
++ } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
++ __l2cap_sock_close(sk, ECONNREFUSED);
++ } else {
++ if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM)
++ l2cap_sock_clear_timer(sk);
+ }
+-
+- read_unlock(&l->lock);
+-
+- return 0;
+ }
+
+-static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
++static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
+ {
+ struct l2cap_chan_list *l;
+ struct l2cap_conn *conn = hcon->l2cap_data;
+@@ -2270,15 +2547,16 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
+ read_lock(&l->lock);
+
+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+- struct l2cap_pinfo *pi = l2cap_pi(sk);
+-
+ bh_lock_sock(sk);
+
+- if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
+- (sk->sk_state == BT_CONNECTED ||
+- sk->sk_state == BT_CONFIG) &&
+- !status && encrypt == 0x00) {
+- __l2cap_sock_close(sk, ECONNREFUSED);
++ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
++ bh_unlock_sock(sk);
++ continue;
++ }
++
++ if (!status && (sk->sk_state == BT_CONNECTED ||
++ sk->sk_state == BT_CONFIG)) {
++ l2cap_check_encryption(sk, encrypt);
+ bh_unlock_sock(sk);
+ continue;
+ }
+@@ -2376,7 +2654,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
+ goto drop;
+
+ skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
+- skb->len);
++ skb->len);
+ conn->rx_len = len - skb->len;
+ } else {
+ BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
+@@ -2398,7 +2676,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
+ }
+
+ skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
+- skb->len);
++ skb->len);
+ conn->rx_len -= skb->len;
+
+ if (!conn->rx_len) {
+@@ -2424,10 +2702,10 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
+ sk_for_each(sk, node, &l2cap_sk_list.head) {
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+
+- str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
++ str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n",
+ batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+ sk->sk_state, btohs(pi->psm), pi->scid, pi->dcid,
+- pi->imtu, pi->omtu, pi->link_mode);
++ pi->imtu, pi->omtu, pi->sec_level);
+ }
+
+ read_unlock_bh(&l2cap_sk_list.lock);
+@@ -2447,7 +2725,7 @@ static const struct proto_ops l2cap_sock_ops = {
+ .accept = l2cap_sock_accept,
+ .getname = l2cap_sock_getname,
+ .sendmsg = l2cap_sock_sendmsg,
+- .recvmsg = bt_sock_recvmsg,
++ .recvmsg = l2cap_sock_recvmsg,
+ .poll = bt_sock_poll,
+ .ioctl = bt_sock_ioctl,
+ .mmap = sock_no_mmap,
+@@ -2469,8 +2747,8 @@ static struct hci_proto l2cap_hci_proto = {
+ .connect_ind = l2cap_connect_ind,
+ .connect_cfm = l2cap_connect_cfm,
+ .disconn_ind = l2cap_disconn_ind,
+- .auth_cfm = l2cap_auth_cfm,
+- .encrypt_cfm = l2cap_encrypt_cfm,
++ .disconn_cfm = l2cap_disconn_cfm,
++ .security_cfm = l2cap_security_cfm,
+ .recv_acldata = l2cap_recv_acldata
+ };
+
+diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
+index acd84fd..1d0fb0f 100644
+--- a/net/bluetooth/rfcomm/core.c
++++ b/net/bluetooth/rfcomm/core.c
+@@ -46,7 +46,7 @@
+ #include <net/bluetooth/l2cap.h>
+ #include <net/bluetooth/rfcomm.h>
+
+-#define VERSION "1.10"
++#define VERSION "1.11"
+
+ static int disable_cfc = 0;
+ static int channel_mtu = -1;
+@@ -223,19 +223,25 @@ static int rfcomm_l2sock_create(struct socket **sock)
+ return err;
+ }
+
+-static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
++static inline int rfcomm_check_security(struct rfcomm_dlc *d)
+ {
+ struct sock *sk = d->session->sock->sk;
++ __u8 auth_type;
+
+- if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
+- if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
+- return 1;
+- } else if (d->link_mode & RFCOMM_LM_AUTH) {
+- if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
+- return 1;
++ switch (d->sec_level) {
++ case BT_SECURITY_HIGH:
++ auth_type = HCI_AT_GENERAL_BONDING_MITM;
++ break;
++ case BT_SECURITY_MEDIUM:
++ auth_type = HCI_AT_GENERAL_BONDING;
++ break;
++ default:
++ auth_type = HCI_AT_NO_BONDING;
++ break;
+ }
+
+- return 0;
++ return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level,
++ auth_type);
+ }
+
+ /* ---- RFCOMM DLCs ---- */
+@@ -388,10 +394,10 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
+ d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
+
+ if (s->state == BT_CONNECTED) {
+- if (rfcomm_check_link_mode(d))
+- set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+- else
++ if (rfcomm_check_security(d))
+ rfcomm_send_pn(s, 1, d);
++ else
++ set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+ }
+
+ rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
+@@ -421,9 +427,16 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
+ d, d->state, d->dlci, err, s);
+
+ switch (d->state) {
+- case BT_CONNECTED:
+- case BT_CONFIG:
+ case BT_CONNECT:
++ case BT_CONFIG:
++ if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
++ set_bit(RFCOMM_AUTH_REJECT, &d->flags);
++ rfcomm_schedule(RFCOMM_SCHED_AUTH);
++ break;
++ }
++ /* Fall through */
++
++ case BT_CONNECTED:
+ d->state = BT_DISCONN;
+ if (skb_queue_empty(&d->tx_queue)) {
+ rfcomm_send_disc(s, d->dlci);
+@@ -434,6 +447,15 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
+ }
+ break;
+
++ case BT_OPEN:
++ case BT_CONNECT2:
++ if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
++ set_bit(RFCOMM_AUTH_REJECT, &d->flags);
++ rfcomm_schedule(RFCOMM_SCHED_AUTH);
++ break;
++ }
++ /* Fall through */
++
+ default:
+ rfcomm_dlc_clear_timer(d);
+
+@@ -636,6 +658,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
+ bacpy(&addr.l2_bdaddr, src);
+ addr.l2_family = AF_BLUETOOTH;
+ addr.l2_psm = 0;
++ addr.l2_cid = 0;
+ *err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (*err < 0)
+ goto failed;
+@@ -657,6 +680,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
+ bacpy(&addr.l2_bdaddr, dst);
+ addr.l2_family = AF_BLUETOOTH;
+ addr.l2_psm = htobs(RFCOMM_PSM);
++ addr.l2_cid = 0;
+ *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
+ if (*err == 0 || *err == -EINPROGRESS)
+ return s;
+@@ -1162,7 +1186,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
+ return 0;
+ }
+
+-static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
++void rfcomm_dlc_accept(struct rfcomm_dlc *d)
+ {
+ struct sock *sk = d->session->sock->sk;
+
+@@ -1175,12 +1199,31 @@ static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
+ d->state_change(d, 0);
+ rfcomm_dlc_unlock(d);
+
+- if (d->link_mode & RFCOMM_LM_MASTER)
++ if (d->role_switch)
+ hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00);
+
+ rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
+ }
+
++static void rfcomm_check_accept(struct rfcomm_dlc *d)
++{
++ if (rfcomm_check_security(d)) {
++ if (d->defer_setup) {
++ set_bit(RFCOMM_DEFER_SETUP, &d->flags);
++ rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
++
++ rfcomm_dlc_lock(d);
++ d->state = BT_CONNECT2;
++ d->state_change(d, 0);
++ rfcomm_dlc_unlock(d);
++ } else
++ rfcomm_dlc_accept(d);
++ } else {
++ set_bit(RFCOMM_AUTH_PENDING, &d->flags);
++ rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
++ }
++}
++
+ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
+ {
+ struct rfcomm_dlc *d;
+@@ -1203,11 +1246,7 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
+ if (d) {
+ if (d->state == BT_OPEN) {
+ /* DLC was previously opened by PN request */
+- if (rfcomm_check_link_mode(d)) {
+- set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+- rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+- } else
+- rfcomm_dlc_accept(d);
++ rfcomm_check_accept(d);
+ }
+ return 0;
+ }
+@@ -1219,11 +1258,7 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
+ d->addr = __addr(s->initiator, dlci);
+ rfcomm_dlc_link(s, d);
+
+- if (rfcomm_check_link_mode(d)) {
+- set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+- rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+- } else
+- rfcomm_dlc_accept(d);
++ rfcomm_check_accept(d);
+ } else {
+ rfcomm_send_dm(s, dlci);
+ }
+@@ -1637,11 +1672,12 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
+ d = list_entry(p, struct rfcomm_dlc, list);
+ if (d->state == BT_CONFIG) {
+ d->mtu = s->mtu;
+- if (rfcomm_check_link_mode(d)) {
++ if (rfcomm_check_security(d)) {
++ rfcomm_send_pn(s, 1, d);
++ } else {
+ set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+ rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+- } else
+- rfcomm_send_pn(s, 1, d);
++ }
+ }
+ }
+ }
+@@ -1717,11 +1753,17 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
+ if (d->out) {
+ rfcomm_send_pn(s, 1, d);
+ rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
+- } else
+- rfcomm_dlc_accept(d);
+- if (d->link_mode & RFCOMM_LM_SECURE) {
+- struct sock *sk = s->sock->sk;
+- hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);
++ } else {
++ if (d->defer_setup) {
++ set_bit(RFCOMM_DEFER_SETUP, &d->flags);
++ rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
++
++ rfcomm_dlc_lock(d);
++ d->state = BT_CONNECT2;
++ d->state_change(d, 0);
++ rfcomm_dlc_unlock(d);
++ } else
++ rfcomm_dlc_accept(d);
+ }
+ continue;
+ } else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
+@@ -1734,6 +1776,9 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
+ continue;
+ }
+
++ if (test_bit(RFCOMM_SEC_PENDING, &d->flags))
++ continue;
++
+ if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
+ continue;
+
+@@ -1876,6 +1921,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
+ bacpy(&addr.l2_bdaddr, ba);
+ addr.l2_family = AF_BLUETOOTH;
+ addr.l2_psm = htobs(RFCOMM_PSM);
++ addr.l2_cid = 0;
+ err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+ if (err < 0) {
+ BT_ERR("Bind failed %d", err);
+@@ -1947,42 +1993,7 @@ static int rfcomm_run(void *unused)
+ return 0;
+ }
+
+-static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status)
+-{
+- struct rfcomm_session *s;
+- struct rfcomm_dlc *d;
+- struct list_head *p, *n;
+-
+- BT_DBG("conn %p status 0x%02x", conn, status);
+-
+- s = rfcomm_session_get(&conn->hdev->bdaddr, &conn->dst);
+- if (!s)
+- return;
+-
+- rfcomm_session_hold(s);
+-
+- list_for_each_safe(p, n, &s->dlcs) {
+- d = list_entry(p, struct rfcomm_dlc, list);
+-
+- if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
+- !(conn->link_mode & HCI_LM_ENCRYPT) && !status)
+- continue;
+-
+- if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
+- continue;
+-
+- if (!status)
+- set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
+- else
+- set_bit(RFCOMM_AUTH_REJECT, &d->flags);
+- }
+-
+- rfcomm_session_put(s);
+-
+- rfcomm_schedule(RFCOMM_SCHED_AUTH);
+-}
+-
+-static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
++static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
+ {
+ struct rfcomm_session *s;
+ struct rfcomm_dlc *d;
+@@ -1999,18 +2010,29 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
+ list_for_each_safe(p, n, &s->dlcs) {
+ d = list_entry(p, struct rfcomm_dlc, list);
+
+- if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
+- (d->state == BT_CONNECTED ||
+- d->state == BT_CONFIG) &&
+- !status && encrypt == 0x00) {
+- __rfcomm_dlc_close(d, ECONNREFUSED);
+- continue;
++ if (test_and_clear_bit(RFCOMM_SEC_PENDING, &d->flags)) {
++ rfcomm_dlc_clear_timer(d);
++ if (status || encrypt == 0x00) {
++ __rfcomm_dlc_close(d, ECONNREFUSED);
++ continue;
++ }
++ }
++
++ if (d->state == BT_CONNECTED && !status && encrypt == 0x00) {
++ if (d->sec_level == BT_SECURITY_MEDIUM) {
++ set_bit(RFCOMM_SEC_PENDING, &d->flags);
++ rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
++ continue;
++ } else if (d->sec_level == BT_SECURITY_HIGH) {
++ __rfcomm_dlc_close(d, ECONNREFUSED);
++ continue;
++ }
+ }
+
+ if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
+ continue;
+
+- if (!status && encrypt)
++ if (!status)
+ set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
+ else
+ set_bit(RFCOMM_AUTH_REJECT, &d->flags);
+@@ -2023,8 +2045,7 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
+
+ static struct hci_cb rfcomm_cb = {
+ .name = "RFCOMM",
+- .auth_cfm = rfcomm_auth_cfm,
+- .encrypt_cfm = rfcomm_encrypt_cfm
++ .security_cfm = rfcomm_security_cfm
+ };
+
+ static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, char *buf)
+diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
+index d3fc6fc..7f48278 100644
+--- a/net/bluetooth/rfcomm/sock.c
++++ b/net/bluetooth/rfcomm/sock.c
+@@ -261,12 +261,19 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
+
+ if (parent) {
+ sk->sk_type = parent->sk_type;
+- pi->link_mode = rfcomm_pi(parent)->link_mode;
++ pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
++
++ pi->sec_level = rfcomm_pi(parent)->sec_level;
++ pi->role_switch = rfcomm_pi(parent)->role_switch;
+ } else {
+- pi->link_mode = 0;
++ pi->dlc->defer_setup = 0;
++
++ pi->sec_level = BT_SECURITY_LOW;
++ pi->role_switch = 0;
+ }
+
+- pi->dlc->link_mode = pi->link_mode;
++ pi->dlc->sec_level = pi->sec_level;
++ pi->dlc->role_switch = pi->role_switch;
+ }
+
+ static struct proto rfcomm_proto = {
+@@ -406,7 +413,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
+ bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
+ rfcomm_pi(sk)->channel = sa->rc_channel;
+
+- d->link_mode = rfcomm_pi(sk)->link_mode;
++ d->sec_level = rfcomm_pi(sk)->sec_level;
++ d->role_switch = rfcomm_pi(sk)->role_switch;
+
+ err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
+ if (!err)
+@@ -554,6 +562,9 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+ struct sk_buff *skb;
+ int sent = 0;
+
++ if (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
++ return -ENOTCONN;
++
+ if (msg->msg_flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+@@ -570,8 +581,11 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+
+ skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
+ msg->msg_flags & MSG_DONTWAIT, &err);
+- if (!skb)
++ if (!skb) {
++ if (sent == 0)
++ sent = err;
+ break;
++ }
+ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
+
+ err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+@@ -630,10 +644,16 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size, int flags)
+ {
+ struct sock *sk = sock->sk;
++ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
+ int err = 0;
+ size_t target, copied = 0;
+ long timeo;
+
++ if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
++ rfcomm_dlc_accept(d);
++ return 0;
++ }
++
+ if (flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+@@ -710,7 +730,7 @@ out:
+ return copied ? : err;
+ }
+
+-static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
++static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen)
+ {
+ struct sock *sk = sock->sk;
+ int err = 0;
+@@ -727,7 +747,14 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
+ break;
+ }
+
+- rfcomm_pi(sk)->link_mode = opt;
++ if (opt & RFCOMM_LM_AUTH)
++ rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
++ if (opt & RFCOMM_LM_ENCRYPT)
++ rfcomm_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
++ if (opt & RFCOMM_LM_SECURE)
++ rfcomm_pi(sk)->sec_level = BT_SECURITY_HIGH;
++
++ rfcomm_pi(sk)->role_switch = (opt & RFCOMM_LM_MASTER);
+ break;
+
+ default:
+@@ -739,12 +766,76 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
+ return err;
+ }
+
+-static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
++static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
++{
++ struct sock *sk = sock->sk;
++ struct bt_security sec;
++ int len, err = 0;
++ u32 opt;
++
++ BT_DBG("sk %p", sk);
++
++ if (level == SOL_RFCOMM)
++ return rfcomm_sock_setsockopt_old(sock, optname, optval, optlen);
++
++ if (level != SOL_BLUETOOTH)
++ return -ENOPROTOOPT;
++
++ lock_sock(sk);
++
++ switch (optname) {
++ case BT_SECURITY:
++ if (sk->sk_type != SOCK_STREAM) {
++ err = -EINVAL;
++ break;
++ }
++
++ sec.level = BT_SECURITY_LOW;
++
++ len = min_t(unsigned int, sizeof(sec), optlen);
++ if (copy_from_user((char *) &sec, optval, len)) {
++ err = -EFAULT;
++ break;
++ }
++
++ if (sec.level > BT_SECURITY_HIGH) {
++ err = -EINVAL;
++ break;
++ }
++
++ rfcomm_pi(sk)->sec_level = sec.level;
++ break;
++
++ case BT_DEFER_SETUP:
++ if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
++ err = -EINVAL;
++ break;
++ }
++
++ if (get_user(opt, (u32 __user *) optval)) {
++ err = -EFAULT;
++ break;
++ }
++
++ bt_sk(sk)->defer_setup = opt;
++ break;
++
++ default:
++ err = -ENOPROTOOPT;
++ break;
++ }
++
++ release_sock(sk);
++ return err;
++}
++
++static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
+ {
+ struct sock *sk = sock->sk;
+ struct sock *l2cap_sk;
+ struct rfcomm_conninfo cinfo;
+ int len, err = 0;
++ u32 opt;
+
+ BT_DBG("sk %p", sk);
+
+@@ -755,12 +846,32 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
+
+ switch (optname) {
+ case RFCOMM_LM:
+- if (put_user(rfcomm_pi(sk)->link_mode, (u32 __user *) optval))
++ switch (rfcomm_pi(sk)->sec_level) {
++ case BT_SECURITY_LOW:
++ opt = RFCOMM_LM_AUTH;
++ break;
++ case BT_SECURITY_MEDIUM:
++ opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
++ break;
++ case BT_SECURITY_HIGH:
++ opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
++ RFCOMM_LM_SECURE;
++ break;
++ default:
++ opt = 0;
++ break;
++ }
++
++ if (rfcomm_pi(sk)->role_switch)
++ opt |= RFCOMM_LM_MASTER;
++
++ if (put_user(opt, (u32 __user *) optval))
+ err = -EFAULT;
+ break;
+
+ case RFCOMM_CONNINFO:
+- if (sk->sk_state != BT_CONNECTED) {
++ if (sk->sk_state != BT_CONNECTED &&
++ !rfcomm_pi(sk)->dlc->defer_setup) {
+ err = -ENOTCONN;
+ break;
+ }
+@@ -785,6 +896,60 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
+ return err;
+ }
+
++static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
++{
++ struct sock *sk = sock->sk;
++ struct bt_security sec;
++ int len, err = 0;
++
++ BT_DBG("sk %p", sk);
++
++ if (level == SOL_RFCOMM)
++ return rfcomm_sock_getsockopt_old(sock, optname, optval, optlen);
++
++ if (level != SOL_BLUETOOTH)
++ return -ENOPROTOOPT;
++
++ if (get_user(len, optlen))
++ return -EFAULT;
++
++ lock_sock(sk);
++
++ switch (optname) {
++ case BT_SECURITY:
++ if (sk->sk_type != SOCK_STREAM) {
++ err = -EINVAL;
++ break;
++ }
++
++ sec.level = rfcomm_pi(sk)->sec_level;
++
++ len = min_t(unsigned int, len, sizeof(sec));
++ if (copy_to_user(optval, (char *) &sec, len))
++ err = -EFAULT;
++
++ break;
++
++ case BT_DEFER_SETUP:
++ if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
++ err = -EINVAL;
++ break;
++ }
++
++ if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
++ err = -EFAULT;
++
++ break;
++
++ default:
++ err = -ENOPROTOOPT;
++ break;
++ }
++
++ release_sock(sk);
++ return err;
++}
++
+ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+ {
+ struct sock *sk __maybe_unused = sock->sk;
+@@ -888,6 +1053,10 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
+
+ done:
+ bh_unlock_sock(parent);
++
++ if (bt_sk(parent)->defer_setup)
++ parent->sk_state_change(parent);
++
+ return result;
+ }
+
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index 46fd8bf..51ae0c3 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -195,7 +195,7 @@ static int sco_connect(struct sock *sk)
+ else
+ type = SCO_LINK;
+
+- hcon = hci_connect(hdev, type, dst, HCI_AT_NO_BONDING);
++ hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
+ if (!hcon)
+ goto done;
+
+@@ -668,7 +668,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char
+ return err;
+ }
+
+-static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
++static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
+ {
+ struct sock *sk = sock->sk;
+ struct sco_options opts;
+@@ -723,6 +723,31 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
+ return err;
+ }
+
++static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
++{
++ struct sock *sk = sock->sk;
++ int len, err = 0;
++
++ BT_DBG("sk %p", sk);
++
++ if (level == SOL_SCO)
++ return sco_sock_getsockopt_old(sock, optname, optval, optlen);
++
++ if (get_user(len, optlen))
++ return -EFAULT;
++
++ lock_sock(sk);
++
++ switch (optname) {
++ default:
++ err = -ENOPROTOOPT;
++ break;
++ }
++
++ release_sock(sk);
++ return err;
++}
++
+ static int sco_sock_release(struct socket *sock)
+ {
+ struct sock *sk = sock->sk;
+@@ -832,10 +857,30 @@ done:
+ /* ----- SCO interface with lower layer (HCI) ----- */
+ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
+ {
++ register struct sock *sk;
++ struct hlist_node *node;
++ int lm = 0;
++
++ if (type != SCO_LINK && type != ESCO_LINK)
++ return 0;
++
+ BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
+
+- /* Always accept connection */
+- return HCI_LM_ACCEPT;
++ /* Find listening sockets */
++ read_lock(&sco_sk_list.lock);
++ sk_for_each(sk, node, &sco_sk_list.head) {
++ if (sk->sk_state != BT_LISTEN)
++ continue;
++
++ if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
++ !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
++ lm |= HCI_LM_ACCEPT;
++ break;
++ }
++ }
++ read_unlock(&sco_sk_list.lock);
++
++ return lm;
+ }
+
+ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
+@@ -857,7 +902,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
+ return 0;
+ }
+
+-static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
++static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
+ {
+ BT_DBG("hcon %p reason %d", hcon, reason);
+
+@@ -940,7 +985,7 @@ static struct hci_proto sco_hci_proto = {
+ .id = HCI_PROTO_SCO,
+ .connect_ind = sco_connect_ind,
+ .connect_cfm = sco_connect_cfm,
+- .disconn_ind = sco_disconn_ind,
++ .disconn_cfm = sco_disconn_cfm,
+ .recv_scodata = sco_recv_scodata
+ };
+
OpenPOWER on IntegriCloud