Commit 5f7bc42b authored by Maksim Krasnyanskiy's avatar Maksim Krasnyanskiy

Merge bk://linux.bkbits.net/linux-2.5

into qualcomm.com:/home/kernel/bt-2.5
parents 7140df08 c3dfa985
...@@ -1394,7 +1394,8 @@ S: USA ...@@ -1394,7 +1394,8 @@ S: USA
N: Marcel Holtmann N: Marcel Holtmann
E: marcel@holtmann.org E: marcel@holtmann.org
W: http://www.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 S: Germany
N: Rob W. W. Hooft N: Rob W. W. Hooft
......
...@@ -328,18 +328,66 @@ M: axboe@suse.de ...@@ -328,18 +328,66 @@ M: axboe@suse.de
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
S: Maintained S: Maintained
BLUETOOTH SUBSYSTEM (BlueZ) BLUETOOTH SUBSYSTEM
P: Maxim Krasnyansky P: Maxim Krasnyansky
M: maxk@qualcomm.com M: maxk@qualcomm.com
W: http://bluez.sf.net W: http://bluez.sf.net
S: Maintained 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 P: Marcel Holtmann
M: marcel@holtmann.org M: marcel@holtmann.org
W: http://www.holtmann.org/linux/bluetooth/ W: http://www.holtmann.org/linux/bluetooth/
S: Maintained 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 BONDING DRIVER
P: Chad Tindel P: Chad Tindel
M: ctindel@users.sourceforge.net M: ctindel@users.sourceforge.net
......
...@@ -302,6 +302,7 @@ static int hci_usb_open(struct hci_dev *hdev) ...@@ -302,6 +302,7 @@ static int hci_usb_open(struct hci_dev *hdev)
hci_usb_bulk_rx_submit(husb); hci_usb_bulk_rx_submit(husb);
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_USB_SCO
if (husb->isoc_iface)
hci_usb_isoc_rx_submit(husb); hci_usb_isoc_rx_submit(husb);
#endif #endif
} else { } else {
......
...@@ -131,7 +131,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *s); ...@@ -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); 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); 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); 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); void bt_accept_enqueue(struct sock *parent, struct sock *sk);
struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock); struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
......
...@@ -304,6 +304,8 @@ struct hci_cp_inquiry { ...@@ -304,6 +304,8 @@ struct hci_cp_inquiry {
__u8 num_rsp; __u8 num_rsp;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_INQUIRY_CANCEL 0x0002
#define OCF_LINK_KEY_REPLY 0x000B #define OCF_LINK_KEY_REPLY 0x000B
#define OCF_LINK_KEY_NEG_REPLY 0x000C #define OCF_LINK_KEY_NEG_REPLY 0x000C
struct hci_cp_link_key_reply { struct hci_cp_link_key_reply {
......
...@@ -220,6 +220,7 @@ struct l2cap_pinfo { ...@@ -220,6 +220,7 @@ struct l2cap_pinfo {
__u32 link_mode; __u32 link_mode;
__u8 conf_state; __u8 conf_state;
__u8 conf_retry;
__u16 conf_mtu; __u16 conf_mtu;
__u8 ident; __u8 ident;
...@@ -234,6 +235,7 @@ struct l2cap_pinfo { ...@@ -234,6 +235,7 @@ struct l2cap_pinfo {
#define L2CAP_CONF_REQ_SENT 0x01 #define L2CAP_CONF_REQ_SENT 0x01
#define L2CAP_CONF_INPUT_DONE 0x02 #define L2CAP_CONF_INPUT_DONE 0x02
#define L2CAP_CONF_OUTPUT_DONE 0x04 #define L2CAP_CONF_OUTPUT_DONE 0x04
#define L2CAP_CONF_MAX_RETRIES 2
void l2cap_load(void); void l2cap_load(void);
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
* *
* $Id: af_bluetooth.c,v 1.3 2002/04/17 17:37:15 maxk Exp $ * $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/config.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -272,39 +272,35 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w ...@@ -272,39 +272,35 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
return mask; 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); DECLARE_WAITQUEUE(wait, current);
long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
int err = 0; int err = 0;
BT_DBG("sk %p", sk); BT_DBG("sk %p", sk);
add_wait_queue(sk->sk_sleep, &wait); add_wait_queue(sk->sk_sleep, &wait);
while (sk->sk_state != BT_CONNECTED) { while (sk->sk_state != state) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (!timeo) { if (!timeo) {
err = -EAGAIN; err = -EAGAIN;
break; break;
} }
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
break;
}
release_sock(sk); release_sock(sk);
timeo = schedule_timeout(timeo); timeo = schedule_timeout(timeo);
lock_sock(sk); lock_sock(sk);
err = 0;
if (sk->sk_state == BT_CONNECTED)
break;
if (sk->sk_err) { if (sk->sk_err) {
err = sock_error(sk); err = sock_error(sk);
break; break;
} }
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
break;
}
} }
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sk_sleep, &wait); remove_wait_queue(sk->sk_sleep, &wait);
......
...@@ -168,11 +168,11 @@ struct bnep_session { ...@@ -168,11 +168,11 @@ struct bnep_session {
u64 mc_filter; u64 mc_filter;
struct socket *sock; struct socket *sock;
struct net_device dev; struct net_device *dev;
struct net_device_stats stats; struct net_device_stats stats;
}; };
int bnep_net_init(struct net_device *dev); void bnep_net_setup(struct net_device *dev);
int bnep_sock_init(void); int bnep_sock_init(void);
int bnep_sock_cleanup(void); int bnep_sock_cleanup(void);
......
...@@ -180,7 +180,7 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) ...@@ -180,7 +180,7 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
s->mc_filter = 0; s->mc_filter = 0;
/* Always send broadcast */ /* Always send broadcast */
set_bit(bnep_mc_hash(s->dev.broadcast), (ulong *) &s->mc_filter); set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
/* Add address ranges to the multicast hash */ /* Add address ranges to the multicast hash */
for (; n > 0; n--) { for (; n > 0; n--) {
...@@ -293,7 +293,7 @@ static u8 __bnep_rx_hlen[] = { ...@@ -293,7 +293,7 @@ static u8 __bnep_rx_hlen[] = {
static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
{ {
struct net_device *dev = &s->dev; struct net_device *dev = s->dev;
struct sk_buff *nskb; struct sk_buff *nskb;
u8 type; u8 type;
...@@ -451,7 +451,7 @@ static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb) ...@@ -451,7 +451,7 @@ static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
static int bnep_session(void *arg) static int bnep_session(void *arg)
{ {
struct bnep_session *s = arg; struct bnep_session *s = arg;
struct net_device *dev = &s->dev; struct net_device *dev = s->dev;
struct sock *sk = s->sock->sk; struct sock *sk = s->sock->sk;
struct sk_buff *skb; struct sk_buff *skb;
wait_queue_t wait; wait_queue_t wait;
...@@ -501,7 +501,7 @@ static int bnep_session(void *arg) ...@@ -501,7 +501,7 @@ static int bnep_session(void *arg)
__bnep_unlink_session(s); __bnep_unlink_session(s);
up_write(&bnep_session_sem); up_write(&bnep_session_sem);
kfree(s); kfree(dev);
return 0; return 0;
} }
...@@ -517,10 +517,13 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) ...@@ -517,10 +517,13 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
baswap((void *) dst, &bt_sk(sock->sk)->dst); baswap((void *) dst, &bt_sk(sock->sk)->dst);
baswap((void *) src, &bt_sk(sock->sk)->src); baswap((void *) src, &bt_sk(sock->sk)->src);
s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL); /* session struct allocated as private part of net_device */
if (!s) dev = alloc_netdev(sizeof(struct bnep_session),
return -ENOMEM; (*req->device) ? req->device : "bnep%d",
memset(s, 0, sizeof(struct bnep_session)); bnep_net_setup);
if (!dev)
return ENOMEM;
down_write(&bnep_session_sem); down_write(&bnep_session_sem);
...@@ -530,20 +533,15 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) ...@@ -530,20 +533,15 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
goto failed; goto failed;
} }
dev = &s->dev; s = dev->priv;
if (*req->device)
strcpy(dev->name, req->device);
else
strcpy(dev->name, "bnep%d");
memset(dev->broadcast, 0xff, ETH_ALEN);
/* This is rx header therefore addresses are swapped. /* This is rx header therefore addresses are swapped.
* ie eh.h_dest is our local address. */ * ie eh.h_dest is our local address. */
memcpy(s->eh.h_dest, &src, ETH_ALEN); memcpy(s->eh.h_dest, &src, ETH_ALEN);
memcpy(s->eh.h_source, &dst, ETH_ALEN); memcpy(s->eh.h_source, &dst, ETH_ALEN);
memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
s->dev = dev;
s->sock = sock; s->sock = sock;
s->role = req->role; s->role = req->role;
s->state = BT_CONNECTED; s->state = BT_CONNECTED;
...@@ -569,8 +567,6 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) ...@@ -569,8 +567,6 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
s->proto_filter[2].end = htons(0x86DD); s->proto_filter[2].end = htons(0x86DD);
#endif #endif
dev->init = bnep_net_init;
dev->priv = s;
err = register_netdev(dev); err = register_netdev(dev);
if (err) { if (err) {
goto failed; goto failed;
...@@ -592,7 +588,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) ...@@ -592,7 +588,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
failed: failed:
up_write(&bnep_session_sem); up_write(&bnep_session_sem);
kfree(s); kfree(dev);
return err; return err;
} }
...@@ -624,7 +620,7 @@ int bnep_del_connection(struct bnep_conndel_req *req) ...@@ -624,7 +620,7 @@ int bnep_del_connection(struct bnep_conndel_req *req)
static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s) static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
{ {
memcpy(ci->dst, s->eh.h_source, ETH_ALEN); memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
strcpy(ci->device, s->dev.name); strcpy(ci->device, s->dev->name);
ci->flags = s->flags; ci->flags = s->flags;
ci->state = s->state; ci->state = s->state;
ci->role = s->role; ci->role = s->role;
......
...@@ -226,11 +226,10 @@ static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -226,11 +226,10 @@ static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
int bnep_net_init(struct net_device *dev) void bnep_net_setup(struct net_device *dev)
{ {
struct bnep_session *s = dev->priv;
memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN); memset(dev->broadcast, 0xff, ETH_ALEN);
dev->addr_len = ETH_ALEN; dev->addr_len = ETH_ALEN;
ether_setup(dev); ether_setup(dev);
...@@ -245,6 +244,4 @@ int bnep_net_init(struct net_device *dev) ...@@ -245,6 +244,4 @@ int bnep_net_init(struct net_device *dev)
dev->watchdog_timeo = HZ * 2; dev->watchdog_timeo = HZ * 2;
dev->tx_timeout = bnep_net_timeout; dev->tx_timeout = bnep_net_timeout;
return 0;
} }
...@@ -394,7 +394,7 @@ int hci_inquiry(unsigned long arg) ...@@ -394,7 +394,7 @@ int hci_inquiry(unsigned long arg)
{ {
struct hci_inquiry_req ir; struct hci_inquiry_req ir;
struct hci_dev *hdev; struct hci_dev *hdev;
int err = 0, do_inquiry = 0; int err = 0, do_inquiry = 0, max_rsp;
long timeo; long timeo;
__u8 *buf, *ptr; __u8 *buf, *ptr;
...@@ -417,16 +417,19 @@ int hci_inquiry(unsigned long arg) ...@@ -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) if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
goto done; 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 /* cache_dump can't sleep. Therefore we allocate temp buffer and then
* copy it to the user space. * 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; err = -ENOMEM;
goto done; goto done;
} }
hci_dev_lock_bh(hdev); 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); hci_dev_unlock_bh(hdev);
BT_DBG("num_rsp %d", ir.num_rsp); BT_DBG("num_rsp %d", ir.num_rsp);
......
...@@ -62,9 +62,22 @@ ...@@ -62,9 +62,22 @@
/* Command Complete OGF LINK_CTL */ /* Command Complete OGF LINK_CTL */
static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) 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); BT_DBG("%s ocf 0x%x", hdev->name, ocf);
switch (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: default:
BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf); BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
break; break;
......
...@@ -75,7 +75,7 @@ static struct hci_sec_filter hci_sec_filter = { ...@@ -75,7 +75,7 @@ static struct hci_sec_filter hci_sec_filter = {
/* OGF_LINK_POLICY */ /* OGF_LINK_POLICY */
{ 0x1200, 0x0, 0x0, 0x0 }, { 0x1200, 0x0, 0x0, 0x0 },
/* OGF_HOST_CTL */ /* OGF_HOST_CTL */
{ 0x80100000, 0x2a, 0x0, 0x0 }, { 0x80100000, 0x202a, 0x0, 0x0 },
/* OGF_INFO_PARAM */ /* OGF_INFO_PARAM */
{ 0x22a, 0x0, 0x0, 0x0 }, { 0x22a, 0x0, 0x0, 0x0 },
/* OGF_STATUS_PARAM */ /* OGF_STATUS_PARAM */
......
...@@ -289,7 +289,7 @@ static void __l2cap_sock_close(struct sock *sk, int reason) ...@@ -289,7 +289,7 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
struct l2cap_disconn_req req; struct l2cap_disconn_req req;
sk->sk_state = BT_DISCONN; 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.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
...@@ -314,11 +314,9 @@ static void __l2cap_sock_close(struct sock *sk, int reason) ...@@ -314,11 +314,9 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
static void l2cap_sock_close(struct sock *sk) static void l2cap_sock_close(struct sock *sk)
{ {
l2cap_sock_clear_timer(sk); l2cap_sock_clear_timer(sk);
lock_sock(sk); lock_sock(sk);
__l2cap_sock_close(sk, ECONNRESET); __l2cap_sock_close(sk, ECONNRESET);
release_sock(sk); release_sock(sk);
l2cap_sock_kill(sk); l2cap_sock_kill(sk);
} }
...@@ -530,8 +528,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al ...@@ -530,8 +528,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
goto done; goto done;
wait: wait:
err = bt_sock_w4_connect(sk, flags); err = bt_sock_wait_state(sk, BT_CONNECTED,
sock_sndtimeo(sk, flags & O_NONBLOCK));
done: done:
release_sock(sk); release_sock(sk);
return err; return err;
...@@ -831,32 +829,39 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch ...@@ -831,32 +829,39 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
static int l2cap_sock_shutdown(struct socket *sock, int how) static int l2cap_sock_shutdown(struct socket *sock, int how)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err = 0;
BT_DBG("sock %p, sk %p", sock, sk); BT_DBG("sock %p, sk %p", sock, sk);
if (!sk) return 0; if (!sk) return 0;
l2cap_sock_clear_timer(sk);
lock_sock(sk); lock_sock(sk);
if (!sk->sk_shutdown) {
sk->sk_shutdown = SHUTDOWN_MASK; sk->sk_shutdown = SHUTDOWN_MASK;
__l2cap_sock_close(sk, ECONNRESET); l2cap_sock_clear_timer(sk);
release_sock(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) static int l2cap_sock_release(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err;
BT_DBG("sock %p, sk %p", sock, sk); BT_DBG("sock %p, sk %p", sock, sk);
if (!sk) return 0; if (!sk) return 0;
err = l2cap_sock_shutdown(sock, 2);
sock_orphan(sk); sock_orphan(sk);
l2cap_sock_close(sk); l2cap_sock_kill(sk);
return 0; return err;
} }
/* ---- L2CAP channels ---- */ /* ---- L2CAP channels ---- */
...@@ -981,9 +986,11 @@ static void l2cap_chan_del(struct sock *sk, int err) ...@@ -981,9 +986,11 @@ static void l2cap_chan_del(struct sock *sk, int err)
} }
sk->sk_state = BT_CLOSED; sk->sk_state = BT_CLOSED;
sk->sk_err = err;
sk->sk_zapped = 1; sk->sk_zapped = 1;
if (err)
sk->sk_err = err;
if (parent) if (parent)
parent->sk_data_ready(parent, 0); parent->sk_data_ready(parent, 0);
else else
...@@ -1518,18 +1525,35 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr ...@@ -1518,18 +1525,35 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
return -ENOENT; return -ENOENT;
if (result) { switch (result) {
struct l2cap_disconn_req req; case L2CAP_CONF_SUCCESS:
break;
/* They didn't like our options. Well... we do not negotiate. case L2CAP_CONF_UNACCEPT:
* Close channel. if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) {
char req[128];
/*
It does not make sense to adjust L2CAP parameters
that are currently defined in the spec. We simply
resend config request that we sent earlier. It is
stupid :) but it helps qualification testing
which expects at least some response from us.
*/ */
l2cap_send_req(conn, L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req);
goto done;
}
default:
sk->sk_state = BT_DISCONN; sk->sk_state = BT_DISCONN;
sk->sk_err = ECONNRESET;
l2cap_sock_set_timer(sk, HZ * 5); l2cap_sock_set_timer(sk, HZ * 5);
{
struct l2cap_disconn_req req;
req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
l2cap_send_req(conn, L2CAP_DISCONN_REQ, sizeof(req), &req); l2cap_send_req(conn, L2CAP_DISCONN_REQ, sizeof(req), &req);
}
goto done; goto done;
} }
...@@ -1590,7 +1614,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd ...@@ -1590,7 +1614,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))) if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
return 0; return 0;
l2cap_chan_del(sk, ECONNABORTED); l2cap_chan_del(sk, 0);
bh_unlock_sock(sk); bh_unlock_sock(sk);
l2cap_sock_kill(sk); l2cap_sock_kill(sk);
......
...@@ -280,13 +280,13 @@ static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci) ...@@ -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) static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
{ {
struct rfcomm_session *s; struct rfcomm_session *s;
u8 dlci = __dlci(0, channel);
int err = 0; int err = 0;
u8 dlci;
BT_DBG("dlc %p state %ld %s %s channel %d dlci %d", BT_DBG("dlc %p state %ld %s %s channel %d",
d, d->state, batostr(src), batostr(dst), channel, dlci); d, d->state, batostr(src), batostr(dst), channel);
if (dlci < 1 || dlci > 62) if (channel < 1 || channel > 30)
return -EINVAL; return -EINVAL;
if (d->state != BT_OPEN && d->state != BT_CLOSED) 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, ...@@ -299,6 +299,8 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
return err; return err;
} }
dlci = __dlci(!s->initiator, channel);
/* Check if DLCI already exists */ /* Check if DLCI already exists */
if (rfcomm_dlc_get(s, dlci)) if (rfcomm_dlc_get(s, dlci))
return -EBUSY; return -EBUSY;
...@@ -715,7 +717,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type) ...@@ -715,7 +717,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
hdr->len = __len8(sizeof(*mcc) + 1); hdr->len = __len8(sizeof(*mcc) + 1);
mcc = (void *) ptr; ptr += sizeof(*mcc); 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); mcc->len = __len8(1);
/* Type that we didn't like */ /* 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 ...@@ -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)); hdr->len = __len8(sizeof(*mcc) + sizeof(*pn));
mcc = (void *) ptr; ptr += sizeof(*mcc); 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)); mcc->len = __len8(sizeof(*pn));
pn = (void *) ptr; ptr += 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 ...@@ -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 = (void *) ptr; ptr += sizeof(*msc);
msc->dlci = __addr(1, dlci); 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++; *ptr = __fcs(buf); ptr++;
...@@ -1085,6 +1131,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) ...@@ -1085,6 +1131,8 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
d->state = BT_CONNECTED; d->state = BT_CONNECTED;
d->state_change(d, 0); d->state_change(d, 0);
rfcomm_dlc_unlock(d); rfcomm_dlc_unlock(d);
rfcomm_send_msc(s, 1, dlci, d->v24_sig);
} else { } else {
rfcomm_send_dm(s, dlci); rfcomm_send_dm(s, dlci);
} }
...@@ -1207,6 +1255,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_ ...@@ -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, /* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
no flow control lines, normal XON/XOFF chars */ 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) { if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
data_bits = __get_rpn_data_bits(rpn->line_settings); data_bits = __get_rpn_data_bits(rpn->line_settings);
if (data_bits != RFCOMM_RPN_DATA_8) { 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_ ...@@ -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->param_mask & RFCOMM_RPN_PM_FLOW) {
if (rpn->flow_ctrl != RFCOMM_RPN_FLOW_NONE) { flow_ctrl = rpn->flow_ctrl;
BT_DBG("RPN flow ctrl mismatch 0x%x", 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; flow_ctrl = RFCOMM_RPN_FLOW_NONE;
rpn_mask ^= RFCOMM_RPN_PM_FLOW; rpn_mask ^= RFCOMM_RPN_PM_FLOW;
} }
} }
if (rpn->param_mask & RFCOMM_RPN_PM_XON) { if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
if (rpn->xon_char != RFCOMM_RPN_XON_CHAR) { xon_char = rpn->xon_char;
BT_DBG("RPN XON char mismatch 0x%x", 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; xon_char = RFCOMM_RPN_XON_CHAR;
rpn_mask ^= RFCOMM_RPN_PM_XON; rpn_mask ^= RFCOMM_RPN_PM_XON;
} }
} }
if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) { if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
if (rpn->xoff_char != RFCOMM_RPN_XOFF_CHAR) { xoff_char = rpn->xoff_char;
BT_DBG("RPN XOFF char mismatch 0x%x", 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; xoff_char = RFCOMM_RPN_XOFF_CHAR;
rpn_mask ^= RFCOMM_RPN_PM_XOFF; rpn_mask ^= RFCOMM_RPN_PM_XOFF;
} }
...@@ -1343,6 +1402,20 @@ static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) ...@@ -1343,6 +1402,20 @@ static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
rfcomm_recv_msc(s, cr, skb); rfcomm_recv_msc(s, cr, skb);
break; 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: case RFCOMM_TEST:
if (cr) if (cr)
rfcomm_send_test(s, 0, skb->data, skb->len); rfcomm_send_test(s, 0, skb->data, skb->len);
...@@ -1533,6 +1606,9 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) ...@@ -1533,6 +1606,9 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
continue; continue;
} }
if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
continue;
if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) && if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
d->mscex == RFCOMM_MSCEX_OK) d->mscex == RFCOMM_MSCEX_OK)
rfcomm_process_tx(d); rfcomm_process_tx(d);
......
...@@ -192,8 +192,10 @@ static void rfcomm_sock_cleanup_listen(struct sock *parent) ...@@ -192,8 +192,10 @@ static void rfcomm_sock_cleanup_listen(struct sock *parent)
BT_DBG("parent %p", parent); BT_DBG("parent %p", parent);
/* Close not yet accepted dlcs */ /* 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_close(sk);
rfcomm_sock_kill(sk);
}
parent->sk_state = BT_CLOSED; parent->sk_state = BT_CLOSED;
parent->sk_zapped = 1; parent->sk_zapped = 1;
...@@ -215,15 +217,10 @@ static void rfcomm_sock_kill(struct sock *sk) ...@@ -215,15 +217,10 @@ static void rfcomm_sock_kill(struct sock *sk)
sock_put(sk); sock_put(sk);
} }
/* Close socket. static void __rfcomm_sock_close(struct sock *sk)
* Must be called on unlocked socket.
*/
static void rfcomm_sock_close(struct sock *sk)
{ {
struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; 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); BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
switch (sk->sk_state) { switch (sk->sk_state) {
...@@ -240,11 +237,17 @@ static void rfcomm_sock_close(struct sock *sk) ...@@ -240,11 +237,17 @@ static void rfcomm_sock_close(struct sock *sk)
default: default:
sk->sk_zapped = 1; sk->sk_zapped = 1;
break; 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); release_sock(sk);
rfcomm_sock_kill(sk);
} }
static void rfcomm_sock_init(struct sock *sk, struct sock *parent) static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
...@@ -374,7 +377,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a ...@@ -374,7 +377,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); err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
if (!err) 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); release_sock(sk);
return err; return err;
...@@ -558,9 +562,6 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -558,9 +562,6 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
int target, err = 0, copied = 0; int target, err = 0, copied = 0;
long timeo; long timeo;
if (sk->sk_state != BT_CONNECTED)
return -EINVAL;
if (flags & MSG_OOB) if (flags & MSG_OOB)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -635,23 +636,6 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -635,23 +636,6 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
return copied ? : err; 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) static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -710,19 +694,42 @@ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned lon ...@@ -710,19 +694,42 @@ static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned lon
return err; 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) static int rfcomm_sock_release(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err;
BT_DBG("sock %p, sk %p", sock, sk); BT_DBG("sock %p, sk %p", sock, sk);
if (!sk) if (!sk)
return 0; return 0;
sock_orphan(sk); err = rfcomm_sock_shutdown(sock, 2);
rfcomm_sock_close(sk);
return 0; sock_orphan(sk);
rfcomm_sock_kill(sk);
return err;
} }
/* ---- RFCOMM core layer callbacks ---- /* ---- RFCOMM core layer callbacks ----
......
...@@ -668,40 +668,8 @@ static int rfcomm_tty_write_room(struct tty_struct *tty) ...@@ -668,40 +668,8 @@ static int rfcomm_tty_write_room(struct tty_struct *tty)
return room; 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) 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); BT_DBG("tty %p cmd 0x%02x", tty, cmd);
switch (cmd) { switch (cmd) {
...@@ -713,18 +681,6 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned ...@@ -713,18 +681,6 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned
BT_DBG("TCSETS is not supported"); BT_DBG("TCSETS is not supported");
return -ENOIOCTLCMD; 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: case TIOCMIWAIT:
BT_DBG("TIOCMIWAIT"); BT_DBG("TIOCMIWAIT");
break; break;
...@@ -851,6 +807,48 @@ static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, ...@@ -851,6 +807,48 @@ static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
return 0; 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 ---- */ /* ---- TTY structure ---- */
static struct tty_driver *rfcomm_tty_driver; static struct tty_driver *rfcomm_tty_driver;
...@@ -870,6 +868,8 @@ static struct tty_operations rfcomm_ops = { ...@@ -870,6 +868,8 @@ static struct tty_operations rfcomm_ops = {
.hangup = rfcomm_tty_hangup, .hangup = rfcomm_tty_hangup,
.wait_until_sent = rfcomm_tty_wait_until_sent, .wait_until_sent = rfcomm_tty_wait_until_sent,
.read_proc = rfcomm_tty_read_proc, .read_proc = rfcomm_tty_read_proc,
.tiocmget = rfcomm_tty_tiocmget,
.tiocmset = rfcomm_tty_tiocmset,
}; };
int rfcomm_init_ttys(void) int rfcomm_init_ttys(void)
...@@ -878,18 +878,17 @@ int rfcomm_init_ttys(void) ...@@ -878,18 +878,17 @@ int rfcomm_init_ttys(void)
if (!rfcomm_tty_driver) if (!rfcomm_tty_driver)
return -1; return -1;
rfcomm_tty_driver->owner = THIS_MODULE, rfcomm_tty_driver->owner = THIS_MODULE;
rfcomm_tty_driver->driver_name = "rfcomm", rfcomm_tty_driver->driver_name = "rfcomm";
rfcomm_tty_driver->devfs_name = "bluetooth/rfcomm/", rfcomm_tty_driver->devfs_name = "bluetooth/rfcomm/";
rfcomm_tty_driver->name = "rfcomm", rfcomm_tty_driver->name = "rfcomm";
rfcomm_tty_driver->major = RFCOMM_TTY_MAJOR, rfcomm_tty_driver->major = RFCOMM_TTY_MAJOR;
rfcomm_tty_driver->minor_start = RFCOMM_TTY_MINOR, rfcomm_tty_driver->minor_start = RFCOMM_TTY_MINOR;
rfcomm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, rfcomm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL, rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW, rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW;
rfcomm_tty_driver->init_termios = tty_std_termios; 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 | CLOCAL;
rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
if (tty_register_driver(rfcomm_tty_driver)) { if (tty_register_driver(rfcomm_tty_driver)) {
......
...@@ -353,8 +353,10 @@ static void sco_sock_cleanup_listen(struct sock *parent) ...@@ -353,8 +353,10 @@ static void sco_sock_cleanup_listen(struct sock *parent)
BT_DBG("parent %p", parent); BT_DBG("parent %p", parent);
/* Close not yet accepted channels */ /* 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_close(sk);
sco_sock_kill(sk);
}
parent->sk_state = BT_CLOSED; parent->sk_state = BT_CLOSED;
parent->sk_zapped = 1; parent->sk_zapped = 1;
...@@ -523,7 +525,8 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen ...@@ -523,7 +525,8 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
if ((err = sco_connect(sk))) if ((err = sco_connect(sk)))
goto done; goto done;
err = bt_sock_w4_connect(sk, flags); err = bt_sock_wait_state(sk, BT_CONNECTED,
sock_sndtimeo(sk, flags & O_NONBLOCK));
done: done:
release_sock(sk); release_sock(sk);
...@@ -727,16 +730,24 @@ int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optva ...@@ -727,16 +730,24 @@ int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optva
static int sco_sock_release(struct socket *sock) static int sco_sock_release(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err = 0;
BT_DBG("sock %p, sk %p", sock, sk); BT_DBG("sock %p, sk %p", sock, sk);
if (!sk) if (!sk)
return 0; return 0;
sock_orphan(sk);
sco_sock_close(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) static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
......
...@@ -77,6 +77,6 @@ EXPORT_SYMBOL(bt_sock_recvmsg); ...@@ -77,6 +77,6 @@ EXPORT_SYMBOL(bt_sock_recvmsg);
EXPORT_SYMBOL(bt_sock_poll); EXPORT_SYMBOL(bt_sock_poll);
EXPORT_SYMBOL(bt_accept_enqueue); EXPORT_SYMBOL(bt_accept_enqueue);
EXPORT_SYMBOL(bt_accept_dequeue); EXPORT_SYMBOL(bt_accept_dequeue);
EXPORT_SYMBOL(bt_sock_w4_connect); EXPORT_SYMBOL(bt_sock_wait_state);
EXPORT_SYMBOL(proc_bt); EXPORT_SYMBOL(proc_bt);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment