|
@@ -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)
|
|
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 @@ out:
|
|
|
|
|
|
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)
|
|
{
|
|
{
|
|
BT_DBG("dev %p", dev);
|
|
BT_DBG("dev %p", dev);
|
|
|
|
|
|
- write_lock_bh(&rfcomm_dev_lock);
|
|
|
|
- list_del_init(&dev->list);
|
|
|
|
- write_unlock_bh(&rfcomm_dev_lock);
|
|
|
|
-
|
|
|
|
|
|
+ set_bit(RFCOMM_TTY_RELEASED, &dev->flags);
|
|
rfcomm_dev_put(dev);
|
|
rfcomm_dev_put(dev);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -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)
|
|
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)
|
|
|
|
|
|
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;
|