aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/rfcomm
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2014-02-09 20:59:02 -0500
committerMarcel Holtmann <marcel@holtmann.org>2014-02-14 16:39:29 -0500
commit136c373bf0e8c445fc028427674817333df602e3 (patch)
tree4416da2995f95409a9b6cd1234089c5574e2caf7 /net/bluetooth/rfcomm
parent7f717b91dd68db1fa01d396d03997ed1b748659f (diff)
Revert "Bluetooth: Always wait for a connection on RFCOMM open()"
This reverts commit 4a2fb3ecc7467c775b154813861f25a0ddc11aa0. This is the second of a 3-patch revert, together with Revert "Bluetooth: Remove rfcomm_carrier_raised()" and Revert "Bluetooth: Move rfcomm_get_device() before rfcomm_dev_activate()". Before commit cad348a17e170451ea8688b532a6ca3e98c63b60, Bluetooth: Implement .activate, .shutdown and .carrier_raised methods, tty_port_block_til_ready() was open-coded in rfcomm_tty_install() as part of the RFCOMM tty open(). Unfortunately, it did not implement non-blocking open nor CLOCAL open, but rather always blocked for carrier. This is not the expected or typical behavior for ttys, and prevents several common terminal programming idioms from working (eg., opening in non-blocking mode to initialize desired termios settings then re-opening for connection). Commit cad348a17e170451ea8688b532a6ca3e98c63b60, Bluetooth: Implement .activate, .shutdown and .carrier_raised methods, added the necessary tty_port methods to use the default tty_port_open(). However, this triggered two important user-space regressions. The first regression involves the complicated mechanism for reparenting the rfcomm tty device to the ACL link device which represents an open link to a specific bluetooth host. This regression causes ModemManager to conclude the rfcomm tty device does not front a modem so it makes no attempt to initialize an attached modem. This regression is caused by the lack of a device_move() if the dlc is already open (and not specifically related to the open-coded block_til_ready()). A more appropriate solution is submitted in "Bluetooth: Fix unsafe RFCOMM device parenting" and "Bluetooth: Fix RFCOMM parent device for reused dlc" The second regression involves "rfcomm bind" and wvdial (a ppp dialer). rfcomm bind creates a device node for a /dev/rfcomm<n>. wvdial opens that device in non-blocking mode (because it expects the connection to have already been established). In addition, subsequent writes to the rfcomm tty device fail (because the link is not yet connected; rfcomm connection begins with the actual tty open()). However, restoring the original behavior (in the patch which this reverts) was undesirable. Firstly, the original reporter notes that a trivial userspace "workaround" already exists: rfcomm connect, which creates the device node and establishes the expected connection. Secondly, the failed writes occur because the rfcomm tty driver does not buffer writes to an unconnected device; this contrasts with the dozen of other tty drivers (in fact, all of them) that do just that. The submitted patch "Bluetooth: Don't fail RFCOMM tty writes" corrects this. Thirdly, it was a long-standing bug to block on non-blocking open, which is re-fixed by revert. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Tested-By: Alexander Holler <holler@ahsoftware.de> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/rfcomm')
-rw-r--r--net/bluetooth/rfcomm/tty.c46
1 files changed, 8 insertions, 38 deletions
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index aeabadeef82b..32ef9f91965c 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -58,7 +58,6 @@ struct rfcomm_dev {
58 uint modem_status; 58 uint modem_status;
59 59
60 struct rfcomm_dlc *dlc; 60 struct rfcomm_dlc *dlc;
61 wait_queue_head_t conn_wait;
62 61
63 struct device *tty_dev; 62 struct device *tty_dev;
64 63
@@ -124,40 +123,8 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
124static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty) 123static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty)
125{ 124{
126 struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port); 125 struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
127 DEFINE_WAIT(wait);
128 int err;
129
130 err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
131 if (err)
132 return err;
133
134 while (1) {
135 prepare_to_wait(&dev->conn_wait, &wait, TASK_INTERRUPTIBLE);
136 126
137 if (dev->dlc->state == BT_CLOSED) { 127 return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
138 err = -dev->err;
139 break;
140 }
141
142 if (dev->dlc->state == BT_CONNECTED)
143 break;
144
145 if (signal_pending(current)) {
146 err = -ERESTARTSYS;
147 break;
148 }
149
150 tty_unlock(tty);
151 schedule();
152 tty_lock(tty);
153 }
154 finish_wait(&dev->conn_wait, &wait);
155
156 if (!err)
157 device_move(dev->tty_dev, rfcomm_get_device(dev),
158 DPM_ORDER_DEV_AFTER_PARENT);
159
160 return err;
161} 128}
162 129
163/* we block the open until the dlc->state becomes BT_CONNECTED */ 130/* we block the open until the dlc->state becomes BT_CONNECTED */
@@ -184,6 +151,7 @@ static const struct tty_port_operations rfcomm_port_ops = {
184 .destruct = rfcomm_dev_destruct, 151 .destruct = rfcomm_dev_destruct,
185 .activate = rfcomm_dev_activate, 152 .activate = rfcomm_dev_activate,
186 .shutdown = rfcomm_dev_shutdown, 153 .shutdown = rfcomm_dev_shutdown,
154 .carrier_raised = rfcomm_dev_carrier_raised,
187}; 155};
188 156
189static struct rfcomm_dev *__rfcomm_dev_get(int id) 157static struct rfcomm_dev *__rfcomm_dev_get(int id)
@@ -290,7 +258,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
290 258
291 tty_port_init(&dev->port); 259 tty_port_init(&dev->port);
292 dev->port.ops = &rfcomm_port_ops; 260 dev->port.ops = &rfcomm_port_ops;
293 init_waitqueue_head(&dev->conn_wait);
294 261
295 skb_queue_head_init(&dev->pending); 262 skb_queue_head_init(&dev->pending);
296 263
@@ -609,9 +576,12 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
609 BT_DBG("dlc %p dev %p err %d", dlc, dev, err); 576 BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
610 577
611 dev->err = err; 578 dev->err = err;
612 wake_up_interruptible(&dev->conn_wait); 579 if (dlc->state == BT_CONNECTED) {
580 device_move(dev->tty_dev, rfcomm_get_device(dev),
581 DPM_ORDER_DEV_AFTER_PARENT);
613 582
614 if (dlc->state == BT_CLOSED) 583 wake_up_interruptible(&dev->port.open_wait);
584 } else if (dlc->state == BT_CLOSED)
615 tty_port_tty_hangup(&dev->port, false); 585 tty_port_tty_hangup(&dev->port, false);
616} 586}
617 587
@@ -1133,7 +1103,7 @@ int __init rfcomm_init_ttys(void)
1133 rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL; 1103 rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
1134 rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 1104 rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
1135 rfcomm_tty_driver->init_termios = tty_std_termios; 1105 rfcomm_tty_driver->init_termios = tty_std_termios;
1136 rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; 1106 rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
1137 rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; 1107 rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
1138 tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); 1108 tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
1139 1109