summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaksim Krasnyanskiy <maxk@qualcomm.com>2003-08-18 06:58:22 -0700
committerMaksim Krasnyanskiy <maxk@qualcomm.com>2003-08-18 06:58:22 -0700
commitf699cb6acd8df6e40e4ccb5354e79afb6b08ec06 (patch)
tree7a9a2376d3e5c81fb88a53d03788e54b7d5c258d
parent068a96bff3db85e237643e0e719b0563c35af8ea (diff)
parent7f3ae704aa21b8f406dc87ac819327252f61fe25 (diff)
Merge bk://linux.bkbits.net/linux-2.5
into qualcomm.com:/home/kernel/bt-2.5
-rw-r--r--CREDITS3
-rw-r--r--MAINTAINERS52
-rw-r--r--drivers/bluetooth/hci_usb.c3
-rw-r--r--include/net/bluetooth/bluetooth.h2
-rw-r--r--include/net/bluetooth/hci.h2
-rw-r--r--net/bluetooth/af_bluetooth.c22
-rw-r--r--net/bluetooth/hci_core.c9
-rw-r--r--net/bluetooth/hci_event.c13
-rw-r--r--net/bluetooth/hci_sock.c2
-rw-r--r--net/bluetooth/l2cap.c39
-rw-r--r--net/bluetooth/rfcomm/core.c102
-rw-r--r--net/bluetooth/rfcomm/sock.c75
-rw-r--r--net/bluetooth/rfcomm/tty.c111
-rw-r--r--net/bluetooth/sco.c21
-rw-r--r--net/bluetooth/syms.c2
15 files changed, 311 insertions, 147 deletions
diff --git a/CREDITS b/CREDITS
index 4c74a608993d..013b795fedeb 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1386,7 +1386,8 @@ S: USA
N: Marcel Holtmann
E: marcel@holtmann.org
W: http://www.holtmann.org
-D: Author of the Linux Bluetooth Subsystem PC Card drivers
+D: Author and maintainer of the various Bluetooth HCI drivers
+D: Various other Bluetooth related patches, cleanups and fixes
S: Germany
N: Rob W. W. Hooft
diff --git a/MAINTAINERS b/MAINTAINERS
index 77762a2248fa..03f2c63f3118 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -334,18 +334,66 @@ M: axboe@suse.de
L: linux-kernel@vger.kernel.org
S: Maintained
-BLUETOOTH SUBSYSTEM (BlueZ)
+BLUETOOTH SUBSYSTEM
P: Maxim Krasnyansky
M: maxk@qualcomm.com
W: http://bluez.sf.net
S: Maintained
-BLUETOOTH SUBSYSTEM (PC Card Drivers)
+BLUETOOTH RFCOMM LAYER
+P: Maxim Krasnyansky
+M: maxk@qualcomm.com
+W: http://bluez.sf.net
+S: Maintained
+
+BLUETOOTH BNEP LAYER
+P: Maxim Krasnyansky
+M: maxk@qualcomm.com
+W: http://bluez.sf.net
+S: Maintained
+
+BLUETOOTH HCI USB DRIVER
+P: Maxim Krasnyansky
+M: maxk@qualcomm.com
+W: http://bluez.sf.net
+S: Maintained
+
+BLUETOOTH HCI UART DRIVER
+P: Maxim Krasnyansky
+M: maxk@qualcomm.com
+W: http://bluez.sf.net
+S: Maintained
+
+BLUETOOTH HCI DTL1 DRIVER
P: Marcel Holtmann
M: marcel@holtmann.org
W: http://www.holtmann.org/linux/bluetooth/
S: Maintained
+BLUETOOTH HCI BLUECARD DRIVER
+P: Marcel Holtmann
+M: marcel@holtmann.org
+W: http://www.holtmann.org/linux/bluetooth/
+S: Maintained
+
+BLUETOOTH HCI BT3C DRIVER
+P: Marcel Holtmann
+M: marcel@holtmann.org
+W: http://www.holtmann.org/linux/bluetooth/
+S: Maintained
+
+BLUETOOTH HCI BTUART DRIVER
+P: Marcel Holtmann
+M: marcel@holtmann.org
+W: http://www.holtmann.org/linux/bluetooth/
+S: Maintained
+
+BLUETOOTH HCI VHCI DRIVER
+P: Maxim Krasnyansky
+M: maxk@qualcomm.com
+W: http://bluez.sf.net
+S: Maintained
+
BONDING DRIVER
P: Chad Tindel
M: ctindel@users.sourceforge.net
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index c3ac4121e793..eccbc5e50142 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -303,7 +303,8 @@ static int hci_usb_open(struct hci_dev *hdev)
hci_usb_bulk_rx_submit(husb);
#ifdef CONFIG_BT_USB_SCO
- hci_usb_isoc_rx_submit(husb);
+ if (husb->isoc_iface)
+ hci_usb_isoc_rx_submit(husb);
#endif
} else {
clear_bit(HCI_RUNNING, &hdev->flags);
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 8dd1886741e0..9adfdc255e8f 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -131,7 +131,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *s);
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int len, int flags);
uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
-int bt_sock_w4_connect(struct sock *sk, int flags);
+int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
void bt_accept_enqueue(struct sock *parent, struct sock *sk);
struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 650b604d262e..228a44322ee0 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -304,6 +304,8 @@ struct hci_cp_inquiry {
__u8 num_rsp;
} __attribute__ ((packed));
+#define OCF_INQUIRY_CANCEL 0x0002
+
#define OCF_LINK_KEY_REPLY 0x000B
#define OCF_LINK_KEY_NEG_REPLY 0x000C
struct hci_cp_link_key_reply {
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index cb1d68d4c98e..817b5be4ec5c 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -27,7 +27,7 @@
*
* $Id: af_bluetooth.c,v 1.3 2002/04/17 17:37:15 maxk Exp $
*/
-#define VERSION "2.2"
+#define VERSION "2.3"
#include <linux/config.h>
#include <linux/module.h>
@@ -272,39 +272,35 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
return mask;
}
-int bt_sock_w4_connect(struct sock *sk, int flags)
+int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
{
DECLARE_WAITQUEUE(wait, current);
- long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
int err = 0;
BT_DBG("sk %p", sk);
add_wait_queue(sk->sk_sleep, &wait);
- while (sk->sk_state != BT_CONNECTED) {
+ while (sk->sk_state != state) {
set_current_state(TASK_INTERRUPTIBLE);
+
if (!timeo) {
err = -EAGAIN;
break;
}
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ break;
+ }
+
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
- err = 0;
- if (sk->sk_state == BT_CONNECTED)
- break;
-
if (sk->sk_err) {
err = sock_error(sk);
break;
}
-
- if (signal_pending(current)) {
- err = sock_intr_errno(timeo);
- break;
- }
}
set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sk_sleep, &wait);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 7905f47157e8..61ef81847c8d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -394,7 +394,7 @@ int hci_inquiry(unsigned long arg)
{
struct hci_inquiry_req ir;
struct hci_dev *hdev;
- int err = 0, do_inquiry = 0;
+ int err = 0, do_inquiry = 0, max_rsp;
long timeo;
__u8 *buf, *ptr;
@@ -417,16 +417,19 @@ int hci_inquiry(unsigned long arg)
if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
goto done;
+ /* for unlimited number of responses we will use buffer with 255 entries */
+ max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
+
/* cache_dump can't sleep. Therefore we allocate temp buffer and then
* copy it to the user space.
*/
- if (!(buf = kmalloc(sizeof(struct inquiry_info) * ir.num_rsp, GFP_KERNEL))) {
+ if (!(buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL))) {
err = -ENOMEM;
goto done;
}
hci_dev_lock_bh(hdev);
- ir.num_rsp = inquiry_cache_dump(hdev, ir.num_rsp, buf);
+ ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
hci_dev_unlock_bh(hdev);
BT_DBG("num_rsp %d", ir.num_rsp);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index cecd730fdfc6..9d70c8c9ff35 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -62,9 +62,22 @@
/* Command Complete OGF LINK_CTL */
static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
{
+ __u8 status;
+
BT_DBG("%s ocf 0x%x", hdev->name, ocf);
switch (ocf) {
+ case OCF_INQUIRY_CANCEL:
+ status = *((__u8 *) skb->data);
+
+ if (status) {
+ BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status);
+ } else {
+ clear_bit(HCI_INQUIRY, &hdev->flags);
+ hci_req_complete(hdev, status);
+ }
+ break;
+
default:
BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
break;
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 1953785a0cea..686abff88dab 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -75,7 +75,7 @@ static struct hci_sec_filter hci_sec_filter = {
/* OGF_LINK_POLICY */
{ 0x1200, 0x0, 0x0, 0x0 },
/* OGF_HOST_CTL */
- { 0x80100000, 0x2a, 0x0, 0x0 },
+ { 0x80100000, 0x202a, 0x0, 0x0 },
/* OGF_INFO_PARAM */
{ 0x22a, 0x0, 0x0, 0x0 },
/* OGF_STATUS_PARAM */
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index d12c0b7926ae..de4f43d76faf 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -290,7 +290,7 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
struct l2cap_disconn_req req;
sk->sk_state = BT_DISCONN;
- l2cap_sock_set_timer(sk, HZ * 5);
+ l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
@@ -315,11 +315,9 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
static void l2cap_sock_close(struct sock *sk)
{
l2cap_sock_clear_timer(sk);
-
lock_sock(sk);
__l2cap_sock_close(sk, ECONNRESET);
release_sock(sk);
-
l2cap_sock_kill(sk);
}
@@ -531,8 +529,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
goto done;
wait:
- err = bt_sock_w4_connect(sk, flags);
-
+ err = bt_sock_wait_state(sk, BT_CONNECTED,
+ sock_sndtimeo(sk, flags & O_NONBLOCK));
done:
release_sock(sk);
return err;
@@ -832,32 +830,39 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
static int l2cap_sock_shutdown(struct socket *sock, int how)
{
struct sock *sk = sock->sk;
+ int err = 0;
BT_DBG("sock %p, sk %p", sock, sk);
if (!sk) return 0;
- l2cap_sock_clear_timer(sk);
-
lock_sock(sk);
- sk->sk_shutdown = SHUTDOWN_MASK;
- __l2cap_sock_close(sk, ECONNRESET);
- release_sock(sk);
+ if (!sk->sk_shutdown) {
+ sk->sk_shutdown = SHUTDOWN_MASK;
+ l2cap_sock_clear_timer(sk);
+ __l2cap_sock_close(sk, 0);
- return 0;
+ if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
+ err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
+ }
+ release_sock(sk);
+ return err;
}
static int l2cap_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
+ int err;
BT_DBG("sock %p, sk %p", sock, sk);
if (!sk) return 0;
+ err = l2cap_sock_shutdown(sock, 2);
+
sock_orphan(sk);
- l2cap_sock_close(sk);
- return 0;
+ l2cap_sock_kill(sk);
+ return err;
}
/* ---- L2CAP channels ---- */
@@ -981,9 +986,11 @@ static void l2cap_chan_del(struct sock *sk, int err)
hci_conn_put(conn->hcon);
}
- sk->sk_state = BT_CLOSED;
- sk->sk_err = err;
+ sk->sk_state = BT_CLOSED;
sk->sk_zapped = 1;
+
+ if (err)
+ sk->sk_err = err;
if (parent)
parent->sk_data_ready(parent, 0);
@@ -1591,7 +1598,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
return 0;
- l2cap_chan_del(sk, ECONNABORTED);
+ l2cap_chan_del(sk, 0);
bh_unlock_sock(sk);
l2cap_sock_kill(sk);
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 4b7c3315ff89..d290c4f40969 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -280,13 +280,13 @@ static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
{
struct rfcomm_session *s;
- u8 dlci = __dlci(0, channel);
int err = 0;
+ u8 dlci;
- BT_DBG("dlc %p state %ld %s %s channel %d dlci %d",
- d, d->state, batostr(src), batostr(dst), channel, dlci);
+ BT_DBG("dlc %p state %ld %s %s channel %d",
+ d, d->state, batostr(src), batostr(dst), channel);
- if (dlci < 1 || dlci > 62)
+ if (channel < 1 || channel > 30)
return -EINVAL;
if (d->state != BT_OPEN && d->state != BT_CLOSED)
@@ -299,6 +299,8 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
return err;
}
+ dlci = __dlci(!s->initiator, channel);
+
/* Check if DLCI already exists */
if (rfcomm_dlc_get(s, dlci))
return -EBUSY;
@@ -715,7 +717,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
hdr->len = __len8(sizeof(*mcc) + 1);
mcc = (void *) ptr; ptr += sizeof(*mcc);
- mcc->type = __mcc_type(s->initiator, RFCOMM_NSC);
+ mcc->type = __mcc_type(cr, RFCOMM_NSC);
mcc->len = __len8(1);
/* Type that we didn't like */
@@ -741,7 +743,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
hdr->len = __len8(sizeof(*mcc) + sizeof(*pn));
mcc = (void *) ptr; ptr += sizeof(*mcc);
- mcc->type = __mcc_type(s->initiator, RFCOMM_PN);
+ mcc->type = __mcc_type(cr, RFCOMM_PN);
mcc->len = __len8(sizeof(*pn));
pn = (void *) ptr; ptr += sizeof(*pn);
@@ -850,7 +852,51 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig
msc = (void *) ptr; ptr += sizeof(*msc);
msc->dlci = __addr(1, dlci);
- msc->v24_sig = v24_sig;
+ msc->v24_sig = v24_sig | 0x01;
+
+ *ptr = __fcs(buf); ptr++;
+
+ return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
+{
+ struct rfcomm_hdr *hdr;
+ struct rfcomm_mcc *mcc;
+ u8 buf[16], *ptr = buf;
+
+ BT_DBG("%p cr %d", s, cr);
+
+ hdr = (void *) ptr; ptr += sizeof(*hdr);
+ hdr->addr = __addr(s->initiator, 0);
+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+ hdr->len = __len8(sizeof(*mcc));
+
+ mcc = (void *) ptr; ptr += sizeof(*mcc);
+ mcc->type = __mcc_type(cr, RFCOMM_FCOFF);
+ mcc->len = __len8(0);
+
+ *ptr = __fcs(buf); ptr++;
+
+ return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
+{
+ struct rfcomm_hdr *hdr;
+ struct rfcomm_mcc *mcc;
+ u8 buf[16], *ptr = buf;
+
+ BT_DBG("%p cr %d", s, cr);
+
+ hdr = (void *) ptr; ptr += sizeof(*hdr);
+ hdr->addr = __addr(s->initiator, 0);
+ hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+ hdr->len = __len8(sizeof(*mcc));
+
+ mcc = (void *) ptr; ptr += sizeof(*mcc);
+ mcc->type = __mcc_type(cr, RFCOMM_FCON);
+ mcc->len = __len8(0);
*ptr = __fcs(buf); ptr++;
@@ -1085,6 +1131,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
d->state = BT_CONNECTED;
d->state_change(d, 0);
rfcomm_dlc_unlock(d);
+
+ rfcomm_send_msc(s, 1, dlci, d->v24_sig);
} else {
rfcomm_send_dm(s, dlci);
}
@@ -1207,6 +1255,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
}
/* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
no flow control lines, normal XON/XOFF chars */
+ if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) {
+ bit_rate = rpn->bit_rate;
+ if (bit_rate != RFCOMM_RPN_BR_115200) {
+ BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
+ bit_rate = RFCOMM_RPN_BR_115200;
+ rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
+ }
+ }
if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
data_bits = __get_rpn_data_bits(rpn->line_settings);
if (data_bits != RFCOMM_RPN_DATA_8) {
@@ -1232,22 +1288,25 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
}
}
if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
- if (rpn->flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
- BT_DBG("RPN flow ctrl mismatch 0x%x", rpn->flow_ctrl);
+ flow_ctrl = rpn->flow_ctrl;
+ if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
+ BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl);
flow_ctrl = RFCOMM_RPN_FLOW_NONE;
rpn_mask ^= RFCOMM_RPN_PM_FLOW;
}
}
if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
- if (rpn->xon_char != RFCOMM_RPN_XON_CHAR) {
- BT_DBG("RPN XON char mismatch 0x%x", rpn->xon_char);
+ xon_char = rpn->xon_char;
+ if (xon_char != RFCOMM_RPN_XON_CHAR) {
+ BT_DBG("RPN XON char mismatch 0x%x", xon_char);
xon_char = RFCOMM_RPN_XON_CHAR;
rpn_mask ^= RFCOMM_RPN_PM_XON;
}
}
if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
- if (rpn->xoff_char != RFCOMM_RPN_XOFF_CHAR) {
- BT_DBG("RPN XOFF char mismatch 0x%x", rpn->xoff_char);
+ xoff_char = rpn->xoff_char;
+ if (xoff_char != RFCOMM_RPN_XOFF_CHAR) {
+ BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char);
xoff_char = RFCOMM_RPN_XOFF_CHAR;
rpn_mask ^= RFCOMM_RPN_PM_XOFF;
}
@@ -1343,6 +1402,20 @@ static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
rfcomm_recv_msc(s, cr, skb);
break;
+ case RFCOMM_FCOFF:
+ if (cr) {
+ set_bit(RFCOMM_TX_THROTTLED, &s->flags);
+ rfcomm_send_fcoff(s, 0);
+ }
+ break;
+
+ case RFCOMM_FCON:
+ if (cr) {
+ clear_bit(RFCOMM_TX_THROTTLED, &s->flags);
+ rfcomm_send_fcon(s, 0);
+ }
+ break;
+
case RFCOMM_TEST:
if (cr)
rfcomm_send_test(s, 0, skb->data, skb->len);
@@ -1533,6 +1606,9 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
continue;
}
+ if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
+ continue;
+
if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
d->mscex == RFCOMM_MSCEX_OK)
rfcomm_process_tx(d);
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index e0aafca1b78d..d657e28cdb37 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -193,8 +193,10 @@ static void rfcomm_sock_cleanup_listen(struct sock *parent)
BT_DBG("parent %p", parent);
/* Close not yet accepted dlcs */
- while ((sk = bt_accept_dequeue(parent, NULL)))
+ while ((sk = bt_accept_dequeue(parent, NULL))) {
rfcomm_sock_close(sk);
+ rfcomm_sock_kill(sk);
+ }
parent->sk_state = BT_CLOSED;
parent->sk_zapped = 1;
@@ -216,15 +218,10 @@ static void rfcomm_sock_kill(struct sock *sk)
sock_put(sk);
}
-/* Close socket.
- * Must be called on unlocked socket.
- */
-static void rfcomm_sock_close(struct sock *sk)
+static void __rfcomm_sock_close(struct sock *sk)
{
struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
- lock_sock(sk);
-
BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
switch (sk->sk_state) {
@@ -241,11 +238,17 @@ static void rfcomm_sock_close(struct sock *sk)
default:
sk->sk_zapped = 1;
break;
- };
+ }
+}
+/* Close socket.
+ * Must be called on unlocked socket.
+ */
+static void rfcomm_sock_close(struct sock *sk)
+{
+ lock_sock(sk);
+ __rfcomm_sock_close(sk);
release_sock(sk);
-
- rfcomm_sock_kill(sk);
}
static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
@@ -375,7 +378,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
if (!err)
- err = bt_sock_w4_connect(sk, flags);
+ err = bt_sock_wait_state(sk, BT_CONNECTED,
+ sock_sndtimeo(sk, flags & O_NONBLOCK));
release_sock(sk);
return err;
@@ -559,9 +563,6 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
int target, err = 0, copied = 0;
long timeo;
- if (sk->sk_state != BT_CONNECTED)
- return -EINVAL;
-
if (flags & MSG_OOB)
return -EOPNOTSUPP;
@@ -636,23 +637,6 @@ out:
return copied ? : err;
}
-static int rfcomm_sock_shutdown(struct socket *sock, int how)
-{
- struct sock *sk = sock->sk;
-
- BT_DBG("sock %p, sk %p", sock, sk);
-
- if (!sk) return 0;
-
- lock_sock(sk);
- sk->sk_shutdown = SHUTDOWN_MASK;
- if (sk->sk_state == BT_CONNECTED)
- rfcomm_dlc_close(rfcomm_pi(sk)->dlc, 0);
- release_sock(sk);
-
- return 0;
-}
-
static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
{
struct sock *sk = sock->sk;
@@ -711,19 +695,42 @@ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned lon
return err;
}
+static int rfcomm_sock_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk = sock->sk;
+ int err = 0;
+
+ BT_DBG("sock %p, sk %p", sock, sk);
+
+ if (!sk) return 0;
+
+ lock_sock(sk);
+ if (!sk->sk_shutdown) {
+ sk->sk_shutdown = SHUTDOWN_MASK;
+ __rfcomm_sock_close(sk);
+
+ if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
+ err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
+ }
+ release_sock(sk);
+ return err;
+}
+
static int rfcomm_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
+ int err;
BT_DBG("sock %p, sk %p", sock, sk);
if (!sk)
return 0;
- sock_orphan(sk);
- rfcomm_sock_close(sk);
+ err = rfcomm_sock_shutdown(sock, 2);
- return 0;
+ sock_orphan(sk);
+ rfcomm_sock_kill(sk);
+ return err;
}
/* ---- RFCOMM core layer callbacks ----
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 2728fc36f85f..468b53d9e1be 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -668,40 +668,8 @@ static int rfcomm_tty_write_room(struct tty_struct *tty)
return room;
}
-static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status)
-{
- u8 v24_sig, mask;
-
- BT_DBG("dlc %p cmd 0x%02x", dlc, cmd);
-
- if (cmd == TIOCMSET)
- v24_sig = 0;
- else
- rfcomm_dlc_get_modem_status(dlc, &v24_sig);
-
- mask = ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) |
- ((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) |
- ((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) |
- ((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) |
- ((status & TIOCM_RI) ? RFCOMM_V24_IC : 0) |
- ((status & TIOCM_CD) ? RFCOMM_V24_DV : 0);
-
- if (cmd == TIOCMBIC)
- v24_sig &= ~mask;
- else
- v24_sig |= mask;
-
- rfcomm_dlc_set_modem_status(dlc, v24_sig);
- return 0;
-}
-
static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
{
- struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
- struct rfcomm_dlc *dlc = dev->dlc;
- uint status;
- int err;
-
BT_DBG("tty %p cmd 0x%02x", tty, cmd);
switch (cmd) {
@@ -713,18 +681,6 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned
BT_DBG("TCSETS is not supported");
return -ENOIOCTLCMD;
- case TIOCMGET:
- BT_DBG("TIOCMGET");
-
- return put_user(dev->modem_status, (unsigned int *)arg);
-
- case TIOCMSET: /* Turns on and off the lines as specified by the mask */
- case TIOCMBIS: /* Turns on the lines as specified by the mask */
- case TIOCMBIC: /* Turns off the lines as specified by the mask */
- if ((err = get_user(status, (unsigned int *)arg)))
- return err;
- return rfcomm_tty_set_modem_status(cmd, dlc, status);
-
case TIOCMIWAIT:
BT_DBG("TIOCMIWAIT");
break;
@@ -851,6 +807,48 @@ static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
return 0;
}
+static int rfcomm_tty_tiocmget(struct tty_struct *tty, struct file *filp)
+{
+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+
+ BT_DBG("tty %p dev %p", tty, dev);
+
+ return dev->modem_status;
+}
+
+static int rfcomm_tty_tiocmset(struct tty_struct *tty, struct file *filp, unsigned int set, unsigned int clear)
+{
+ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+ struct rfcomm_dlc *dlc = dev->dlc;
+ u8 v24_sig;
+
+ BT_DBG("tty %p dev %p set 0x%02x clear 0x%02x", tty, dev, set, clear);
+
+ rfcomm_dlc_get_modem_status(dlc, &v24_sig);
+
+ if (set & TIOCM_DSR || set & TIOCM_DTR)
+ v24_sig |= RFCOMM_V24_RTC;
+ if (set & TIOCM_RTS || set & TIOCM_CTS)
+ v24_sig |= RFCOMM_V24_RTR;
+ if (set & TIOCM_RI)
+ v24_sig |= RFCOMM_V24_IC;
+ if (set & TIOCM_CD)
+ v24_sig |= RFCOMM_V24_DV;
+
+ if (clear & TIOCM_DSR || clear & TIOCM_DTR)
+ v24_sig &= ~RFCOMM_V24_RTC;
+ if (clear & TIOCM_RTS || clear & TIOCM_CTS)
+ v24_sig &= ~RFCOMM_V24_RTR;
+ if (clear & TIOCM_RI)
+ v24_sig &= ~RFCOMM_V24_IC;
+ if (clear & TIOCM_CD)
+ v24_sig &= ~RFCOMM_V24_DV;
+
+ rfcomm_dlc_set_modem_status(dlc, v24_sig);
+
+ return 0;
+}
+
/* ---- TTY structure ---- */
static struct tty_driver *rfcomm_tty_driver;
@@ -870,6 +868,8 @@ static struct tty_operations rfcomm_ops = {
.hangup = rfcomm_tty_hangup,
.wait_until_sent = rfcomm_tty_wait_until_sent,
.read_proc = rfcomm_tty_read_proc,
+ .tiocmget = rfcomm_tty_tiocmget,
+ .tiocmset = rfcomm_tty_tiocmset,
};
int rfcomm_init_ttys(void)
@@ -878,18 +878,17 @@ int rfcomm_init_ttys(void)
if (!rfcomm_tty_driver)
return -1;
- rfcomm_tty_driver->owner = THIS_MODULE,
- rfcomm_tty_driver->driver_name = "rfcomm",
- rfcomm_tty_driver->devfs_name = "bluetooth/rfcomm/",
- rfcomm_tty_driver->name = "rfcomm",
- rfcomm_tty_driver->major = RFCOMM_TTY_MAJOR,
- rfcomm_tty_driver->minor_start = RFCOMM_TTY_MINOR,
- rfcomm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
- rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
- rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW,
- rfcomm_tty_driver->init_termios = tty_std_termios;
- rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+ rfcomm_tty_driver->owner = THIS_MODULE;
+ rfcomm_tty_driver->driver_name = "rfcomm";
+ rfcomm_tty_driver->devfs_name = "bluetooth/rfcomm/";
+ rfcomm_tty_driver->name = "rfcomm";
+ rfcomm_tty_driver->major = RFCOMM_TTY_MAJOR;
+ rfcomm_tty_driver->minor_start = RFCOMM_TTY_MINOR;
+ rfcomm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+ rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+ rfcomm_tty_driver->init_termios = tty_std_termios;
+ rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
if (tty_register_driver(rfcomm_tty_driver)) {
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index b1ef7c76663d..2eba7dd2e29d 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -354,8 +354,10 @@ static void sco_sock_cleanup_listen(struct sock *parent)
BT_DBG("parent %p", parent);
/* Close not yet accepted channels */
- while ((sk = bt_accept_dequeue(parent, NULL)))
+ while ((sk = bt_accept_dequeue(parent, NULL))) {
sco_sock_close(sk);
+ sco_sock_kill(sk);
+ }
parent->sk_state = BT_CLOSED;
parent->sk_zapped = 1;
@@ -524,7 +526,8 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
if ((err = sco_connect(sk)))
goto done;
- err = bt_sock_w4_connect(sk, flags);
+ err = bt_sock_wait_state(sk, BT_CONNECTED,
+ sock_sndtimeo(sk, flags & O_NONBLOCK));
done:
release_sock(sk);
@@ -728,16 +731,24 @@ int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optva
static int sco_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
+ int err = 0;
BT_DBG("sock %p, sk %p", sock, sk);
if (!sk)
return 0;
-
- sock_orphan(sk);
+
sco_sock_close(sk);
- return 0;
+ if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) {
+ lock_sock(sk);
+ err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
+ release_sock(sk);
+ }
+
+ sock_orphan(sk);
+ sco_sock_kill(sk);
+ return err;
}
static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
diff --git a/net/bluetooth/syms.c b/net/bluetooth/syms.c
index e8da89c1bf2b..587e7bdee32e 100644
--- a/net/bluetooth/syms.c
+++ b/net/bluetooth/syms.c
@@ -77,6 +77,6 @@ EXPORT_SYMBOL(bt_sock_recvmsg);
EXPORT_SYMBOL(bt_sock_poll);
EXPORT_SYMBOL(bt_accept_enqueue);
EXPORT_SYMBOL(bt_accept_dequeue);
-EXPORT_SYMBOL(bt_sock_w4_connect);
+EXPORT_SYMBOL(bt_sock_wait_state);
EXPORT_SYMBOL(proc_bt);