From 574e02abaf816b582685805f0c1150ca9f1f18ee Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 4 May 2012 08:27:43 -0500 Subject: [PATCH 1/3] rtlwifi: fix for race condition when firmware is cached In commit b0302ab, the rtlwifi family of drivers was converted to use asynchronous firmware loading. Unfortumately, the implementation was racy, and the ieee80211 routines could be started before rtl_init_core() was called to setup the data. This patch fixes the bug noted in https://bugzilla.kernel.org/show_bug.cgi?id=43187. Reported-by: Joshua Roys Tested-by: Neptune Ning Signed-off-by: Larry Finger Cc: Stable [3.3] Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/pci.c | 16 ++++++++-------- drivers/net/wireless/rtlwifi/usb.c | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index cc15fdb36060..67f9430ee197 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1851,14 +1851,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, /*like read eeprom and so on */ rtlpriv->cfg->ops->read_eeprom_info(hw); - if (rtlpriv->cfg->ops->init_sw_vars(hw)) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n"); - err = -ENODEV; - goto fail3; - } - - rtlpriv->cfg->ops->init_sw_leds(hw); - /*aspm */ rtl_pci_init_aspm(hw); @@ -1877,6 +1869,14 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, goto fail3; } + if (rtlpriv->cfg->ops->init_sw_vars(hw)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n"); + err = -ENODEV; + goto fail3; + } + + rtlpriv->cfg->ops->init_sw_leds(hw); + err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group); if (err) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index d04dbda13f5a..a6049d7d51b3 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -971,11 +971,6 @@ int __devinit rtl_usb_probe(struct usb_interface *intf, rtlpriv->cfg->ops->read_chip_version(hw); /*like read eeprom and so on */ rtlpriv->cfg->ops->read_eeprom_info(hw); - if (rtlpriv->cfg->ops->init_sw_vars(hw)) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n"); - goto error_out; - } - rtlpriv->cfg->ops->init_sw_leds(hw); err = _rtl_usb_init(hw); if (err) goto error_out; @@ -987,6 +982,11 @@ int __devinit rtl_usb_probe(struct usb_interface *intf, "Can't allocate sw for mac80211\n"); goto error_out; } + if (rtlpriv->cfg->ops->init_sw_vars(hw)) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n"); + goto error_out; + } + rtlpriv->cfg->ops->init_sw_leds(hw); return 0; error_out: From a7d7723ae7c0178d715c06c5621e8fd8014ba92f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sun, 13 May 2012 03:20:07 -0300 Subject: [PATCH 2/3] Bluetooth: notify userspace of security level change It fixes L2CAP socket based security level elevation during a connection. The HID profile needs this (for keyboards) and it is the only way to achieve the security level elevation when using the management interface to talk to the kernel (hence the management enabling patch being the one that exposes this issue). It enables the userspace a security level change when the socket is already connected and create a way to notify the socket the result of the request. At the moment of the request the socket is made non writable, if the request fails the connections closes, otherwise the socket is made writable again, POLL_OUT is emmited. Signed-off-by: Gustavo Padovan Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg Signed-off-by: John W. Linville --- include/net/bluetooth/bluetooth.h | 1 + net/bluetooth/af_bluetooth.c | 2 +- net/bluetooth/hci_event.c | 7 +++++++ net/bluetooth/l2cap_core.c | 5 +++++ net/bluetooth/l2cap_sock.c | 12 ++++++++---- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 262ebd1747d4..a65910bda381 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -191,6 +191,7 @@ struct bt_sock { struct list_head accept_q; struct sock *parent; u32 defer_setup; + bool suspended; }; struct bt_sock_list { diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 72eb187a5f60..6fb68a9743af 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -450,7 +450,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wa sk->sk_state == BT_CONFIG) return mask; - if (sock_writeable(sk)) + if (!bt_sk(sk)->suspended && sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6c065254afc0..53680fe84628 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2039,6 +2039,12 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + if (ev->status && conn->state == BT_CONNECTED) { + hci_acl_disconn(conn, 0x13); + hci_conn_put(conn); + goto unlock; + } + if (conn->state == BT_CONFIG) { if (!ev->status) conn->state = BT_CONNECTED; @@ -2049,6 +2055,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * hci_encrypt_cfm(conn, ev->status, ev->encrypt); } +unlock: hci_dev_unlock(hdev); } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 94552b33d528..6f9c25b633a6 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4589,6 +4589,11 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (!status && (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)) { + struct sock *sk = chan->sk; + + bt_sk(sk)->suspended = false; + sk->sk_state_change(sk); + l2cap_check_encryption(chan, encrypt); l2cap_chan_unlock(chan); continue; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 29122ed28ea9..04e7c172d49c 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -592,10 +592,14 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch sk->sk_state = BT_CONFIG; chan->state = BT_CONFIG; - /* or for ACL link, under defer_setup time */ - } else if (sk->sk_state == BT_CONNECT2 && - bt_sk(sk)->defer_setup) { - err = l2cap_chan_check_security(chan); + /* or for ACL link */ + } else if ((sk->sk_state == BT_CONNECT2 && + bt_sk(sk)->defer_setup) || + sk->sk_state == BT_CONNECTED) { + if (!l2cap_chan_check_security(chan)) + bt_sk(sk)->suspended = true; + else + sk->sk_state_change(sk); } else { err = -EINVAL; } From 671267bf3aac3dae0555730b07ef29c042e325b2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 12 May 2012 16:11:50 -0300 Subject: [PATCH 3/3] Bluetooth: mgmt: Fix device_connected sending order The mgmt_ev_device_connected signal must be sent before any event indications happen for sockets associated with the connection. Otherwise e.g. device authorization for the sockets will fail with ENOTCONN as user space things that there is no baseband link. This patch fixes the issue by ensuring that the device_connected event if sent (if it hasn't been so already) as soon as the first ACL data packet arrives from the remote device. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: John W. Linville --- net/bluetooth/hci_core.c | 8 ++++++++ net/bluetooth/hci_event.c | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index edfd61addcec..d6dc44cd15b0 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2784,6 +2784,14 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) if (conn) { hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF); + hci_dev_lock(hdev); + if (test_bit(HCI_MGMT, &hdev->dev_flags) && + !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) + mgmt_device_connected(hdev, &conn->dst, conn->type, + conn->dst_type, 0, NULL, 0, + conn->dev_class); + hci_dev_unlock(hdev); + /* Send to upper protocol */ l2cap_recv_acldata(conn, skb, flags); return; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 53680fe84628..1266f78fa8e3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2109,7 +2109,7 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff goto unlock; } - if (!ev->status) { + if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) { struct hci_cp_remote_name_req cp; memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &conn->dst); @@ -2878,7 +2878,7 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b if (conn->state != BT_CONFIG) goto unlock; - if (!ev->status) { + if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) { struct hci_cp_remote_name_req cp; memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &conn->dst);