diff options
Diffstat (limited to 'freed-ora/current/F-12/git-bluetooth.patch')
-rw-r--r-- | freed-ora/current/F-12/git-bluetooth.patch | 3344 |
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 + }; + |