Bluetooth: Rename __rfcomm_dev_get() to __rfcomm_dev_lookup()
[firefly-linux-kernel-4.4.55.git] / net / bluetooth / rfcomm / tty.c
index f9c0980abeeac9eaf1d94d70f3e001fd6e1f0870..4a38b5454ab00bee82a0cca4b4496e0952919f45 100644 (file)
@@ -51,6 +51,8 @@ struct rfcomm_dev {
        unsigned long           flags;
        int                     err;
 
+       unsigned long           status;         /* don't export to userspace */
+
        bdaddr_t                src;
        bdaddr_t                dst;
        u8                      channel;
@@ -58,7 +60,6 @@ struct rfcomm_dev {
        uint                    modem_status;
 
        struct rfcomm_dlc       *dlc;
-       wait_queue_head_t       conn_wait;
 
        struct device           *tty_dev;
 
@@ -83,10 +84,6 @@ static void rfcomm_dev_destruct(struct tty_port *port)
 
        BT_DBG("dev %p dlc %p", dev, dlc);
 
-       spin_lock(&rfcomm_dev_lock);
-       list_del(&dev->list);
-       spin_unlock(&rfcomm_dev_lock);
-
        rfcomm_dlc_lock(dlc);
        /* Detach DLC if it's owned by this dev */
        if (dlc->owner == dev)
@@ -97,6 +94,10 @@ static void rfcomm_dev_destruct(struct tty_port *port)
 
        tty_unregister_device(rfcomm_tty_driver, dev->id);
 
+       spin_lock(&rfcomm_dev_lock);
+       list_del(&dev->list);
+       spin_unlock(&rfcomm_dev_lock);
+
        kfree(dev);
 
        /* It's safe to call module_put() here because socket still
@@ -104,60 +105,20 @@ static void rfcomm_dev_destruct(struct tty_port *port)
        module_put(THIS_MODULE);
 }
 
-static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
-{
-       struct hci_dev *hdev;
-       struct hci_conn *conn;
-
-       hdev = hci_get_route(&dev->dst, &dev->src);
-       if (!hdev)
-               return NULL;
-
-       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
-
-       hci_dev_put(hdev);
-
-       return conn ? &conn->dev : NULL;
-}
-
 /* device-specific initialization: open the dlc */
 static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty)
 {
        struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
-       DEFINE_WAIT(wait);
-       int err;
-
-       err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
-       if (err)
-               return err;
-
-       while (1) {
-               prepare_to_wait(&dev->conn_wait, &wait, TASK_INTERRUPTIBLE);
-
-               if (dev->dlc->state == BT_CLOSED) {
-                       err = -dev->err;
-                       break;
-               }
-
-               if (dev->dlc->state == BT_CONNECTED)
-                       break;
 
-               if (signal_pending(current)) {
-                       err = -ERESTARTSYS;
-                       break;
-               }
-
-               tty_unlock(tty);
-               schedule();
-               tty_lock(tty);
-       }
-       finish_wait(&dev->conn_wait, &wait);
+       return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
+}
 
-       if (!err)
-               device_move(dev->tty_dev, rfcomm_get_device(dev),
-                           DPM_ORDER_DEV_AFTER_PARENT);
+/* we block the open until the dlc->state becomes BT_CONNECTED */
+static int rfcomm_dev_carrier_raised(struct tty_port *port)
+{
+       struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
 
-       return err;
+       return (dev->dlc->state == BT_CONNECTED);
 }
 
 /* device-specific cleanup: close the dlc */
@@ -176,9 +137,10 @@ static const struct tty_port_operations rfcomm_port_ops = {
        .destruct = rfcomm_dev_destruct,
        .activate = rfcomm_dev_activate,
        .shutdown = rfcomm_dev_shutdown,
+       .carrier_raised = rfcomm_dev_carrier_raised,
 };
 
-static struct rfcomm_dev *__rfcomm_dev_get(int id)
+static struct rfcomm_dev *__rfcomm_dev_lookup(int id)
 {
        struct rfcomm_dev *dev;
 
@@ -195,20 +157,41 @@ static struct rfcomm_dev *rfcomm_dev_get(int id)
 
        spin_lock(&rfcomm_dev_lock);
 
-       dev = __rfcomm_dev_get(id);
+       dev = __rfcomm_dev_lookup(id);
 
-       if (dev) {
-               if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
-                       dev = NULL;
-               else
-                       tty_port_get(&dev->port);
-       }
+       if (dev && !tty_port_get(&dev->port))
+               dev = NULL;
 
        spin_unlock(&rfcomm_dev_lock);
 
        return dev;
 }
 
+static void rfcomm_reparent_device(struct rfcomm_dev *dev)
+{
+       struct hci_dev *hdev;
+       struct hci_conn *conn;
+
+       hdev = hci_get_route(&dev->dst, &dev->src);
+       if (!hdev)
+               return;
+
+       /* The lookup results are unsafe to access without the
+        * hci device lock (FIXME: why is this not documented?)
+        */
+       hci_dev_lock(hdev);
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
+
+       /* Just because the acl link is in the hash table is no
+        * guarantee the sysfs device has been added ...
+        */
+       if (conn && device_is_registered(&conn->dev))
+               device_move(dev->tty_dev, &conn->dev, DPM_ORDER_DEV_AFTER_PARENT);
+
+       hci_dev_unlock(hdev);
+       hci_dev_put(hdev);
+}
+
 static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
 {
        struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
@@ -282,7 +265,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 
        tty_port_init(&dev->port);
        dev->port.ops = &rfcomm_port_ops;
-       init_waitqueue_head(&dev->conn_wait);
 
        skb_queue_head_init(&dev->pending);
 
@@ -334,6 +316,7 @@ out:
                goto free;
        }
 
+       rfcomm_reparent_device(dev);
        dev_set_drvdata(dev->tty_dev, dev);
 
        if (device_create_file(dev->tty_dev, &dev_attr_address) < 0)
@@ -412,6 +395,14 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg)
                dlc = rfcomm_pi(sk)->dlc;
                rfcomm_dlc_hold(dlc);
        } else {
+               /* Validate the channel is unused */
+               dlc = rfcomm_dlc_exists(&req.src, &req.dst, req.channel);
+               if (IS_ERR(dlc))
+                       return PTR_ERR(dlc);
+               else if (dlc) {
+                       rfcomm_dlc_put(dlc);
+                       return -EBUSY;
+               }
                dlc = rfcomm_dlc_alloc(GFP_KERNEL);
                if (!dlc)
                        return -ENOMEM;
@@ -452,6 +443,12 @@ static int rfcomm_release_dev(void __user *arg)
                return -EPERM;
        }
 
+       /* only release once */
+       if (test_and_set_bit(RFCOMM_DEV_RELEASED, &dev->status)) {
+               tty_port_put(&dev->port);
+               return -EALREADY;
+       }
+
        if (req.flags & (1 << RFCOMM_HANGUP_NOW))
                rfcomm_dlc_close(dev->dlc, 0);
 
@@ -462,8 +459,7 @@ static int rfcomm_release_dev(void __user *arg)
                tty_kref_put(tty);
        }
 
-       if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
-           !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+       if (!test_bit(RFCOMM_TTY_OWNED, &dev->status))
                tty_port_put(&dev->port);
 
        tty_port_put(&dev->port);
@@ -497,7 +493,7 @@ static int rfcomm_get_dev_list(void __user *arg)
        spin_lock(&rfcomm_dev_lock);
 
        list_for_each_entry(dev, &rfcomm_dev_list, list) {
-               if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+               if (!tty_port_get(&dev->port))
                        continue;
                (di + n)->id      = dev->id;
                (di + n)->flags   = dev->flags;
@@ -505,6 +501,7 @@ static int rfcomm_get_dev_list(void __user *arg)
                (di + n)->channel = dev->channel;
                bacpy(&(di + n)->src, &dev->src);
                bacpy(&(di + n)->dst, &dev->dst);
+               tty_port_put(&dev->port);
                if (++n >= dev_num)
                        break;
        }
@@ -601,9 +598,11 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
        BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
 
        dev->err = err;
-       wake_up_interruptible(&dev->conn_wait);
+       if (dlc->state == BT_CONNECTED) {
+               rfcomm_reparent_device(dev);
 
-       if (dlc->state == BT_CLOSED)
+               wake_up_interruptible(&dev->port.open_wait);
+       } else if (dlc->state == BT_CLOSED)
                tty_port_tty_hangup(&dev->port, false);
 }
 
@@ -703,8 +702,10 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
         * when the last process closes the tty. The behaviour is expected by
         * userspace.
         */
-       if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+       if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
+               set_bit(RFCOMM_TTY_OWNED, &dev->status);
                tty_port_put(&dev->port);
+       }
 
        return 0;
 }
@@ -1125,7 +1126,7 @@ int __init rfcomm_init_ttys(void)
        rfcomm_tty_driver->subtype      = SERIAL_TYPE_NORMAL;
        rfcomm_tty_driver->flags        = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        rfcomm_tty_driver->init_termios = tty_std_termios;
-       rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
        rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
        tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);