diff options
| author | Maksim Krasnyanskiy <maxk@qualcomm.com> | 2003-08-18 06:58:22 -0700 |
|---|---|---|
| committer | Maksim Krasnyanskiy <maxk@qualcomm.com> | 2003-08-18 06:58:22 -0700 |
| commit | f699cb6acd8df6e40e4ccb5354e79afb6b08ec06 (patch) | |
| tree | 7a9a2376d3e5c81fb88a53d03788e54b7d5c258d | |
| parent | 068a96bff3db85e237643e0e719b0563c35af8ea (diff) | |
| parent | 7f3ae704aa21b8f406dc87ac819327252f61fe25 (diff) | |
Merge bk://linux.bkbits.net/linux-2.5
into qualcomm.com:/home/kernel/bt-2.5
| -rw-r--r-- | CREDITS | 3 | ||||
| -rw-r--r-- | MAINTAINERS | 52 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_usb.c | 3 | ||||
| -rw-r--r-- | include/net/bluetooth/bluetooth.h | 2 | ||||
| -rw-r--r-- | include/net/bluetooth/hci.h | 2 | ||||
| -rw-r--r-- | net/bluetooth/af_bluetooth.c | 22 | ||||
| -rw-r--r-- | net/bluetooth/hci_core.c | 9 | ||||
| -rw-r--r-- | net/bluetooth/hci_event.c | 13 | ||||
| -rw-r--r-- | net/bluetooth/hci_sock.c | 2 | ||||
| -rw-r--r-- | net/bluetooth/l2cap.c | 39 | ||||
| -rw-r--r-- | net/bluetooth/rfcomm/core.c | 102 | ||||
| -rw-r--r-- | net/bluetooth/rfcomm/sock.c | 75 | ||||
| -rw-r--r-- | net/bluetooth/rfcomm/tty.c | 111 | ||||
| -rw-r--r-- | net/bluetooth/sco.c | 21 | ||||
| -rw-r--r-- | net/bluetooth/syms.c | 2 |
15 files changed, 311 insertions, 147 deletions
@@ -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); |
