summaryrefslogtreecommitdiff
path: root/net/bluetooth/rfcomm
diff options
context:
space:
mode:
Diffstat (limited to 'net/bluetooth/rfcomm')
-rw-r--r--net/bluetooth/rfcomm/core.c58
-rw-r--r--net/bluetooth/rfcomm/sock.c5
-rw-r--r--net/bluetooth/rfcomm/tty.c36
3 files changed, 69 insertions, 30 deletions
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index e99010ce8bb2..468df3b953f6 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -27,7 +27,6 @@
* $Id: core.c,v 1.42 2002/10/01 23:26:25 maxk Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -53,8 +52,10 @@
#define BT_DBG(D...)
#endif
-#define VERSION "1.7"
+#define VERSION "1.8"
+static int disable_cfc = 0;
+static int channel_mtu = -1;
static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU;
static struct task_struct *rfcomm_thread;
@@ -273,10 +274,10 @@ static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
struct rfcomm_dlc *rfcomm_dlc_alloc(gfp_t prio)
{
- struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio);
+ struct rfcomm_dlc *d = kzalloc(sizeof(*d), prio);
+
if (!d)
return NULL;
- memset(d, 0, sizeof(*d));
init_timer(&d->timer);
d->timer.function = rfcomm_dlc_timeout;
@@ -289,6 +290,7 @@ struct rfcomm_dlc *rfcomm_dlc_alloc(gfp_t prio)
rfcomm_dlc_clear_state(d);
BT_DBG("%p", d);
+
return d;
}
@@ -522,10 +524,10 @@ int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
/* ---- RFCOMM sessions ---- */
static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
{
- struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ struct rfcomm_session *s = kzalloc(sizeof(*s), GFP_KERNEL);
+
if (!s)
return NULL;
- memset(s, 0, sizeof(*s));
BT_DBG("session %p sock %p", s, sock);
@@ -534,7 +536,7 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
s->sock = sock;
s->mtu = RFCOMM_DEFAULT_MTU;
- s->cfc = RFCOMM_CFC_UNKNOWN;
+ s->cfc = disable_cfc ? RFCOMM_CFC_DISABLED : RFCOMM_CFC_UNKNOWN;
/* Do not increment module usage count for listening sessions.
* Otherwise we won't be able to unload the module. */
@@ -642,7 +644,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = htobs(RFCOMM_PSM);
*err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
- if (*err == 0 || *err == -EAGAIN)
+ if (*err == 0 || *err == -EINPROGRESS)
return s;
rfcomm_session_del(s);
@@ -811,7 +813,10 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
pn->credits = 0;
}
- pn->mtu = htobs(d->mtu);
+ if (cr && channel_mtu >= 0)
+ pn->mtu = htobs(channel_mtu);
+ else
+ pn->mtu = htobs(d->mtu);
*ptr = __fcs(buf); ptr++;
@@ -1150,6 +1155,8 @@ static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
{
+ struct sock *sk = d->session->sock->sk;
+
BT_DBG("dlc %p", d);
rfcomm_send_ua(d->session, d->dlci);
@@ -1159,6 +1166,9 @@ static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
d->state_change(d, 0);
rfcomm_dlc_unlock(d);
+ if (d->link_mode & RFCOMM_LM_MASTER)
+ hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00);
+
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
}
@@ -1223,17 +1233,24 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d",
d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
- if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) {
- d->cfc = s->cfc = RFCOMM_CFC_ENABLED;
+ if ((pn->flow_ctrl == 0xf0 && s->cfc != RFCOMM_CFC_DISABLED) ||
+ pn->flow_ctrl == 0xe0) {
+ d->cfc = RFCOMM_CFC_ENABLED;
d->tx_credits = pn->credits;
} else {
- d->cfc = s->cfc = RFCOMM_CFC_DISABLED;
+ d->cfc = RFCOMM_CFC_DISABLED;
set_bit(RFCOMM_TX_THROTTLED, &d->flags);
}
+ if (s->cfc == RFCOMM_CFC_UNKNOWN)
+ s->cfc = d->cfc;
+
d->priority = pn->priority;
- d->mtu = s->mtu = btohs(pn->mtu);
+ d->mtu = btohs(pn->mtu);
+
+ if (cr && d->mtu > s->mtu)
+ d->mtu = s->mtu;
return 0;
}
@@ -1760,6 +1777,11 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
s = rfcomm_session_add(nsock, BT_OPEN);
if (s) {
rfcomm_session_hold(s);
+
+ /* We should adjust MTU on incoming sessions.
+ * L2CAP MTU minus UIH header and FCS. */
+ s->mtu = min(l2cap_pi(nsock->sk)->omtu, l2cap_pi(nsock->sk)->imtu) - 5;
+
rfcomm_schedule(RFCOMM_SCHED_RX);
} else
sock_release(nsock);
@@ -2036,7 +2058,7 @@ static int __init rfcomm_init(void)
kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
- class_create_file(&bt_class, &class_attr_rfcomm_dlc);
+ class_create_file(bt_class, &class_attr_rfcomm_dlc);
rfcomm_init_sockets();
@@ -2051,7 +2073,7 @@ static int __init rfcomm_init(void)
static void __exit rfcomm_exit(void)
{
- class_remove_file(&bt_class, &class_attr_rfcomm_dlc);
+ class_remove_file(bt_class, &class_attr_rfcomm_dlc);
hci_unregister_cb(&rfcomm_cb);
@@ -2074,6 +2096,12 @@ static void __exit rfcomm_exit(void)
module_init(rfcomm_init);
module_exit(rfcomm_exit);
+module_param(disable_cfc, bool, 0644);
+MODULE_PARM_DESC(disable_cfc, "Disable credit based flow control");
+
+module_param(channel_mtu, int, 0644);
+MODULE_PARM_DESC(channel_mtu, "Default MTU for the RFCOMM channel");
+
module_param(l2cap_mtu, uint, 0644);
MODULE_PARM_DESC(l2cap_mtu, "Default MTU for the L2CAP connection");
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 757d2dd3b02f..220fee04e7f2 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -27,7 +27,6 @@
* $Id: sock.c,v 1.24 2002/10/03 01:00:34 maxk Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -945,7 +944,7 @@ int __init rfcomm_init_sockets(void)
if (err < 0)
goto error;
- class_create_file(&bt_class, &class_attr_rfcomm);
+ class_create_file(bt_class, &class_attr_rfcomm);
BT_INFO("RFCOMM socket layer initialized");
@@ -959,7 +958,7 @@ error:
void __exit rfcomm_cleanup_sockets(void)
{
- class_remove_file(&bt_class, &class_attr_rfcomm);
+ class_remove_file(bt_class, &class_attr_rfcomm);
if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
BT_ERR("RFCOMM socket layer unregistration failed");
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 74368f79ee5d..26f322737db0 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -27,7 +27,6 @@
* $Id: tty.c,v 1.24 2002/10/03 01:54:38 holtmann Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
@@ -39,6 +38,7 @@
#include <linux/skbuff.h>
#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/rfcomm.h>
#ifndef CONFIG_BT_RFCOMM_DEBUG
@@ -162,6 +162,24 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
return dev;
}
+static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
+{
+ struct hci_dev *hdev;
+ struct hci_conn *conn;
+
+ hdev = hci_get_route(&dev->dst, &dev->src);
+ if (!hdev)
+ return NULL;
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
+ if (!conn)
+ return NULL;
+
+ hci_dev_put(hdev);
+
+ return &conn->dev;
+}
+
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
{
struct rfcomm_dev *dev;
@@ -170,10 +188,9 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
BT_DBG("id %d channel %d", req->dev_id, req->channel);
- dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- memset(dev, 0, sizeof(struct rfcomm_dev));
write_lock_bh(&rfcomm_dev_lock);
@@ -246,7 +263,7 @@ out:
return err;
}
- tty_register_device(rfcomm_tty_driver, dev->id, NULL);
+ tty_register_device(rfcomm_tty_driver, dev->id, rfcomm_get_device(dev));
return dev->id;
}
@@ -480,12 +497,8 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
- if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
- tty_buffer_request_room(tty, skb->len);
- tty_insert_flip_string(tty, skb->data, skb->len);
- tty_flip_buffer_push(tty);
- } else
- tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
+ tty_insert_flip_string(tty, skb->data, skb->len);
+ tty_flip_buffer_push(tty);
kfree_skb(skb);
}
@@ -1025,13 +1038,12 @@ int rfcomm_init_ttys(void)
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 | TTY_DRIVER_NO_DEVFS;
+ rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
rfcomm_tty_driver->init_termios = tty_std_termios;
rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);