Commit b3c5cf79 authored by Ville Tervo's avatar Ville Tervo Committed by Greg Kroah-Hartman

Keep rfcomm_dev on the list until it is freed

This patch changes the RFCOMM TTY release process so that the TTY is kept
on the list until it is really freed. A new device flag is used to keep
track of released TTYs.
Signed-off-by: default avatarVille Tervo <ville.tervo@nokia.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 772aa8b1
...@@ -323,6 +323,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc ...@@ -323,6 +323,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc
#define RFCOMM_RELEASE_ONHUP 1 #define RFCOMM_RELEASE_ONHUP 1
#define RFCOMM_HANGUP_NOW 2 #define RFCOMM_HANGUP_NOW 2
#define RFCOMM_TTY_ATTACHED 3 #define RFCOMM_TTY_ATTACHED 3
#define RFCOMM_TTY_RELEASED 4
struct rfcomm_dev_req { struct rfcomm_dev_req {
s16 dev_id; s16 dev_id;
......
...@@ -95,6 +95,10 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev) ...@@ -95,6 +95,10 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
BT_DBG("dev %p dlc %p", dev, dlc); BT_DBG("dev %p dlc %p", dev, dlc);
write_lock_bh(&rfcomm_dev_lock);
list_del_init(&dev->list);
write_unlock_bh(&rfcomm_dev_lock);
rfcomm_dlc_lock(dlc); rfcomm_dlc_lock(dlc);
/* Detach DLC if it's owned by this dev */ /* Detach DLC if it's owned by this dev */
if (dlc->owner == dev) if (dlc->owner == dev)
...@@ -156,8 +160,13 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id) ...@@ -156,8 +160,13 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
read_lock(&rfcomm_dev_lock); read_lock(&rfcomm_dev_lock);
dev = __rfcomm_dev_get(id); dev = __rfcomm_dev_get(id);
if (dev)
rfcomm_dev_hold(dev); if (dev) {
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
dev = NULL;
else
rfcomm_dev_hold(dev);
}
read_unlock(&rfcomm_dev_lock); read_unlock(&rfcomm_dev_lock);
...@@ -265,6 +274,12 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) ...@@ -265,6 +274,12 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL); dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
if (IS_ERR(dev->tty_dev)) {
list_del(&dev->list);
kfree(dev);
return PTR_ERR(dev->tty_dev);
}
return dev->id; return dev->id;
} }
...@@ -272,10 +287,7 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev) ...@@ -272,10 +287,7 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
{ {
BT_DBG("dev %p", dev); BT_DBG("dev %p", dev);
write_lock_bh(&rfcomm_dev_lock); set_bit(RFCOMM_TTY_RELEASED, &dev->flags);
list_del_init(&dev->list);
write_unlock_bh(&rfcomm_dev_lock);
rfcomm_dev_put(dev); rfcomm_dev_put(dev);
} }
...@@ -329,7 +341,7 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg) ...@@ -329,7 +341,7 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg)
if (copy_from_user(&req, arg, sizeof(req))) if (copy_from_user(&req, arg, sizeof(req)))
return -EFAULT; return -EFAULT;
BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags); BT_DBG("sk %p dev_id %d flags 0x%x", sk, req.dev_id, req.flags);
if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
...@@ -370,7 +382,7 @@ static int rfcomm_release_dev(void __user *arg) ...@@ -370,7 +382,7 @@ static int rfcomm_release_dev(void __user *arg)
if (copy_from_user(&req, arg, sizeof(req))) if (copy_from_user(&req, arg, sizeof(req)))
return -EFAULT; return -EFAULT;
BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags); BT_DBG("dev_id %d flags 0x%x", req.dev_id, req.flags);
if (!(dev = rfcomm_dev_get(req.dev_id))) if (!(dev = rfcomm_dev_get(req.dev_id)))
return -ENODEV; return -ENODEV;
...@@ -419,6 +431,8 @@ static int rfcomm_get_dev_list(void __user *arg) ...@@ -419,6 +431,8 @@ static int rfcomm_get_dev_list(void __user *arg)
list_for_each(p, &rfcomm_dev_list) { list_for_each(p, &rfcomm_dev_list) {
struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list); struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
continue;
(di + n)->id = dev->id; (di + n)->id = dev->id;
(di + n)->flags = dev->flags; (di + n)->flags = dev->flags;
(di + n)->state = dev->dlc->state; (di + n)->state = dev->dlc->state;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment