commit b1fb06830dc870d862f7f80e276130c0ab84d59f Author: Wei Yongjun 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 Signed-off-by: Marcel Holtmann commit 7585b97a48180f754ebdade1be94092e36bef365 Author: Wei Yongjun 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 Signed-off-by: Marcel Holtmann commit 2ae9a6be5f476f3512839a4d11a8f432bfd2914c Author: Dave Young 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 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: [] __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:[] 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] [] ? trace_hardirqs_on_caller+0x72/0x1c0 [ 2845.743742] [] ? lock_acquire+0x76/0xa0 [ 2845.743742] [] ? skb_dequeue+0x1d/0x70 [ 2845.743742] [] ? _spin_lock_irqsave+0x45/0x80 [ 2845.743742] [] ? skb_dequeue+0x1d/0x70 [ 2845.743742] [] ? skb_dequeue+0x1d/0x70 [ 2845.743742] [] ? skb_queue_purge+0x14/0x20 [ 2845.743742] [] ? hci_conn_del+0x10a/0x1c0 [bluetooth] [ 2845.743742] [] ? l2cap_disconn_ind+0x59/0xb0 [l2cap] [ 2845.743742] [] ? hci_conn_del_sysfs+0x8e/0xd0 [bluetooth] [ 2845.743742] [] ? hci_event_packet+0x5f8/0x31c0 [bluetooth] [ 2845.743742] [] ? sock_def_readable+0x59/0x80 [ 2845.743742] [] ? _read_unlock+0x1d/0x20 [ 2845.743742] [] ? hci_send_to_sock+0xe9/0x1d0 [bluetooth] [ 2845.743742] [] ? trace_hardirqs_on+0xb/0x10 [ 2845.743742] [] ? hci_rx_task+0x2ba/0x490 [bluetooth] [ 2845.743742] [] ? tasklet_action+0x31/0xc0 [ 2845.743742] [] ? tasklet_action+0x4c/0xc0 [ 2845.743742] [] ? __do_softirq+0xa7/0x170 [ 2845.743742] [] ? ack_apic_level+0x5c/0x1c0 [ 2845.743742] [] ? do_softirq+0x57/0x60 [ 2845.743742] [] ? irq_exit+0x7c/0x90 [ 2845.743742] [] ? do_IRQ+0x4b/0x90 [ 2845.743742] [] ? irq_exit+0x75/0x90 [ 2845.743742] [] ? common_interrupt+0x2c/0x34 [ 2845.743742] [] ? mwait_idle+0x4f/0x70 [ 2845.743742] [] ? cpu_idle+0x65/0xb0 [ 2845.743742] [] ? 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 ff 86 c4 00 00 00 89 f0 e8 56 a9 ff ff 85 c0 0f 85 6e 03 00 [ 2845.743742] EIP: [] __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] [] warn_slowpath+0x86/0xa0 [ 2845.743742] [] ? trace_hardirqs_off+0xb/0x10 [ 2845.743742] [] ? up+0x14/0x40 [ 2845.743742] [] ? release_console_sem+0x31/0x1e0 [ 2845.743742] [] ? _spin_lock_irqsave+0x6b/0x80 [ 2845.743742] [] ? trace_hardirqs_off+0xb/0x10 [ 2845.743742] [] ? _read_lock_irqsave+0x40/0x80 [ 2845.743742] [] ? release_console_sem+0x1c2/0x1e0 [ 2845.743742] [] ? up+0x14/0x40 [ 2845.743742] [] ? trace_hardirqs_off+0xb/0x10 [ 2845.743742] [] ? __mutex_unlock_slowpath+0x97/0x160 [ 2845.743742] [] ? mutex_trylock+0xb3/0x180 [ 2845.743742] [] ? mutex_unlock+0x8/0x10 [ 2845.743742] [] smp_call_function_many+0x151/0x200 [ 2845.743742] [] ? stop_this_cpu+0x0/0x40 [ 2845.743742] [] smp_call_function+0x21/0x30 [ 2845.743742] [] native_smp_send_stop+0x1e/0x50 [ 2845.743742] [] panic+0x55/0x110 [ 2845.743742] [] oops_end+0xb8/0xc0 [ 2845.743742] [] die+0x4f/0x70 [ 2845.743742] [] do_page_fault+0x269/0x610 [ 2845.743742] [] ? do_page_fault+0x0/0x610 [ 2845.743742] [] error_code+0x77/0x7c [ 2845.743742] [] ? __lock_acquire+0x6c/0xa80 [ 2845.743742] [] ? trace_hardirqs_on_caller+0x72/0x1c0 [ 2845.743742] [] lock_acquire+0x76/0xa0 [ 2845.743742] [] ? skb_dequeue+0x1d/0x70 [ 2845.743742] [] _spin_lock_irqsave+0x45/0x80 [ 2845.743742] [] ? skb_dequeue+0x1d/0x70 [ 2845.743742] [] skb_dequeue+0x1d/0x70 [ 2845.743742] [] skb_queue_purge+0x14/0x20 [ 2845.743742] [] hci_conn_del+0x10a/0x1c0 [bluetooth] [ 2845.743742] [] ? l2cap_disconn_ind+0x59/0xb0 [l2cap] [ 2845.743742] [] ? hci_conn_del_sysfs+0x8e/0xd0 [bluetooth] [ 2845.743742] [] hci_event_packet+0x5f8/0x31c0 [bluetooth] [ 2845.743742] [] ? sock_def_readable+0x59/0x80 [ 2845.743742] [] ? _read_unlock+0x1d/0x20 [ 2845.743742] [] ? hci_send_to_sock+0xe9/0x1d0 [bluetooth] [ 2845.743742] [] ? trace_hardirqs_on+0xb/0x10 [ 2845.743742] [] hci_rx_task+0x2ba/0x490 [bluetooth] [ 2845.743742] [] ? tasklet_action+0x31/0xc0 [ 2845.743742] [] tasklet_action+0x4c/0xc0 [ 2845.743742] [] __do_softirq+0xa7/0x170 [ 2845.743742] [] ? ack_apic_level+0x5c/0x1c0 [ 2845.743742] [] do_softirq+0x57/0x60 [ 2845.743742] [] irq_exit+0x7c/0x90 [ 2845.743742] [] do_IRQ+0x4b/0x90 [ 2845.743742] [] ? irq_exit+0x75/0x90 [ 2845.743742] [] common_interrupt+0x2c/0x34 [ 2845.743742] [] ? mwait_idle+0x4f/0x70 [ 2845.743742] [] cpu_idle+0x65/0xb0 [ 2845.743742] [] 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] [] warn_slowpath+0x86/0xa0 [ 2845.743742] [] ? warn_slowpath+0x10/0xa0 [ 2845.743742] [] ? trace_hardirqs_off+0xb/0x10 [ 2845.743742] [] ? up+0x14/0x40 [ 2845.743742] [] ? release_console_sem+0x31/0x1e0 [ 2845.743742] [] ? _spin_lock_irqsave+0x6b/0x80 [ 2845.743742] [] ? trace_hardirqs_off+0xb/0x10 [ 2845.743742] [] ? _read_lock_irqsave+0x40/0x80 [ 2845.743742] [] ? release_console_sem+0x1c2/0x1e0 [ 2845.743742] [] ? up+0x14/0x40 [ 2845.743742] [] smp_call_function_single+0x8e/0x110 [ 2845.743742] [] ? stop_this_cpu+0x0/0x40 [ 2845.743742] [] ? cpumask_next_and+0x1f/0x40 [ 2845.743742] [] smp_call_function_many+0x11a/0x200 [ 2845.743742] [] ? stop_this_cpu+0x0/0x40 [ 2845.743742] [] smp_call_function+0x21/0x30 [ 2845.743742] [] native_smp_send_stop+0x1e/0x50 [ 2845.743742] [] panic+0x55/0x110 [ 2845.743742] [] oops_end+0xb8/0xc0 [ 2845.743742] [] die+0x4f/0x70 [ 2845.743742] [] do_page_fault+0x269/0x610 [ 2845.743742] [] ? do_page_fault+0x0/0x610 [ 2845.743742] [] error_code+0x77/0x7c [ 2845.743742] [] ? __lock_acquire+0x6c/0xa80 [ 2845.743742] [] ? trace_hardirqs_on_caller+0x72/0x1c0 [ 2845.743742] [] lock_acquire+0x76/0xa0 [ 2845.743742] [] ? skb_dequeue+0x1d/0x70 [ 2845.743742] [] _spin_lock_irqsave+0x45/0x80 [ 2845.743742] [] ? skb_dequeue+0x1d/0x70 [ 2845.743742] [] skb_dequeue+0x1d/0x70 [ 2845.743742] [] skb_queue_purge+0x14/0x20 [ 2845.743742] [] hci_conn_del+0x10a/0x1c0 [bluetooth] [ 2845.743742] [] ? l2cap_disconn_ind+0x59/0xb0 [l2cap] [ 2845.743742] [] ? hci_conn_del_sysfs+0x8e/0xd0 [bluetooth] [ 2845.743742] [] hci_event_packet+0x5f8/0x31c0 [bluetooth] [ 2845.743742] [] ? sock_def_readable+0x59/0x80 [ 2845.743742] [] ? _read_unlock+0x1d/0x20 [ 2845.743742] [] ? hci_send_to_sock+0xe9/0x1d0 [bluetooth] [ 2845.743742] [] ? trace_hardirqs_on+0xb/0x10 [ 2845.743742] [] hci_rx_task+0x2ba/0x490 [bluetooth] [ 2845.743742] [] ? tasklet_action+0x31/0xc0 [ 2845.743742] [] tasklet_action+0x4c/0xc0 [ 2845.743742] [] __do_softirq+0xa7/0x170 [ 2845.743742] [] ? ack_apic_level+0x5c/0x1c0 [ 2845.743742] [] do_softirq+0x57/0x60 [ 2845.743742] [] irq_exit+0x7c/0x90 [ 2845.743742] [] do_IRQ+0x4b/0x90 [ 2845.743742] [] ? irq_exit+0x75/0x90 [ 2845.743742] [] common_interrupt+0x2c/0x34 [ 2845.743742] [] ? mwait_idle+0x4f/0x70 [ 2845.743742] [] cpu_idle+0x65/0xb0 [ 2845.743742] [] 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 Signed-off-by: Marcel Holtmann commit 2526d3d8b2f671a7d36cc486af984052cd5a690f Author: Marcel Holtmann 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 Signed-off-by: Marcel Holtmann commit 37e62f5516cfb210e64fe53457932df4341b0ad1 Author: Marcel Holtmann 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 commit 2a517ca687232adc8f14893730644da712010ffc Author: Marcel Holtmann 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 commit 8bf4794174659b06d43cc5e290cd384757374613 Author: Marcel Holtmann 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 commit d5f2d2be68876f65dd051b978a7b66265fde9ffd Author: Marcel Holtmann 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 commit 96a3183322cba1a2846771b067c99b9d6f481263 Author: Marcel Holtmann 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 commit 00ae4af91d8c5b6814e2bb3bfaaf743845f989eb Author: Marcel Holtmann 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 commit 2950f21acb0f6b8fcd964485c2ebf1e06545ac20 Author: Marcel Holtmann 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 commit f29972de8e7476706ab3c01304a505e7c95d9040 Author: Marcel Holtmann 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 commit e1027a7c69700301d14db03d2e049ee60c4f92df Author: Marcel Holtmann 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 commit 435fef20acfc48f46476abad55b0cd3aa47b8365 Author: Marcel Holtmann 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 commit 6a8d3010b313d99adbb28f1826fac0234395bb26 Author: Marcel Holtmann 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 commit 984947dc64f82bc6cafa4d84ba1a139718f634a8 Author: Marcel Holtmann 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 commit 657e17b03c80bec817975984d221bef716f83558 Author: Marcel Holtmann 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 commit 0684e5f9fb9e3f7e168ab831dfca693bcb44805b Author: Marcel Holtmann 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 commit efc7688b557dd1be10eead7399b315efcb1dbc74 Author: Marcel Holtmann 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 commit 255c76014af74165428e7aa16414b857e2bdccf2 Author: Marcel Holtmann 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 commit 43c2e57f94c15744495fee564610aa24602b3824 Author: Marcel Holtmann 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 commit 6e1031a40029492c10509e8c3dcac9b611438ccb Author: Jaikumar Ganesh 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 Signed-off-by: Marcel Holtmann commit 34a55eda483e8177c9044f93fd2c9107f02bf1c7 Author: Andre Haupt 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 Signed-off-by: Marcel Holtmann commit dd2efd03b49d56ae795c71335bc7358022514c32 Author: Dave Young 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 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 Signed-off-by: Marcel Holtmann commit 5f9018af004fa8635bbbe3ab2dc61e8a686edfaa Author: Marcel Holtmann 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 commit 0588d94fd7e414367a7ae517569d2222441c255f Author: Marcel Holtmann 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 commit f62e4323ab43c59e7cd7f72c1eb392d7c767ce5a Author: Marcel Holtmann 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 commit 8c84b83076b5062f59b6167cdda90d9e5124aa71 Author: Marcel Holtmann 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 Signed-off-by: Marcel Holtmann commit 9f2c8a03fbb3048cf38b158f87aa0c3c09bca084 Author: Marcel Holtmann 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 commit 2af6b9d518ddfbc4d6990d5f9c9b1a05341c1cef Author: Marcel Holtmann 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 commit 8c1b235594fbab9a13240a1dac12ea9fd99b6440 Author: Marcel Holtmann 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 commit c89b6e6bda4c8021195778f47567d0cc9dbfe7ec Author: Marcel Holtmann 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 Signed-off-by: Marcel Holtmann commit 71aeeaa1fd88fe7446391e0553336f0e0c2cfe6a Author: Marcel Holtmann 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 commit f66dc81f44d918ee1aa1a9d821bb2f25c7592bc0 Author: Marcel Holtmann 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 commit bb23c0ab824653be4aa7dfca15b07b3059717004 Author: Marcel Holtmann 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 commit c4f912e155504e94dd4f3d63c378dab0ff03dbda Author: Marcel Holtmann 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 commit d58daf42d29a3a4a4d4be46cf47ceee096789680 Author: Marcel Holtmann 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 commit 91aa35a5aa3540223066bf6b51c935418c63a35d Author: Victor Shcherbatyuk 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 Signed-off-by: Marcel Holtmann 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 #include -#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 -#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 #include -#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 #include -#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 };