diff options
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/af_bluetooth.c | 23 | ||||
-rw-r--r-- | net/bluetooth/bnep/core.c | 27 | ||||
-rw-r--r-- | net/bluetooth/bnep/netdev.c | 1 | ||||
-rw-r--r-- | net/bluetooth/bnep/sock.c | 1 | ||||
-rw-r--r-- | net/bluetooth/cmtp/capi.c | 5 | ||||
-rw-r--r-- | net/bluetooth/cmtp/core.c | 4 | ||||
-rw-r--r-- | net/bluetooth/cmtp/sock.c | 1 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 140 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 49 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 233 | ||||
-rw-r--r-- | net/bluetooth/hci_sock.c | 1 | ||||
-rw-r--r-- | net/bluetooth/hci_sysfs.c | 325 | ||||
-rw-r--r-- | net/bluetooth/hidp/Kconfig | 3 | ||||
-rw-r--r-- | net/bluetooth/hidp/core.c | 27 | ||||
-rw-r--r-- | net/bluetooth/hidp/sock.c | 1 | ||||
-rw-r--r-- | net/bluetooth/l2cap.c | 376 | ||||
-rw-r--r-- | net/bluetooth/lib.c | 1 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/core.c | 58 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/sock.c | 5 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/tty.c | 36 | ||||
-rw-r--r-- | net/bluetooth/sco.c | 17 |
21 files changed, 948 insertions, 386 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 469eda0f0dfd..305a099b7477 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -24,7 +24,6 @@ /* Bluetooth address family and sockets. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -49,7 +48,7 @@ #define BT_DBG(D...) #endif -#define VERSION "2.8" +#define VERSION "2.10" /* Bluetooth sockets */ #define BT_MAX_PROTO 8 @@ -277,7 +276,7 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo) set_current_state(TASK_INTERRUPTIBLE); if (!timeo) { - err = -EAGAIN; + err = -EINPROGRESS; break; } @@ -308,13 +307,21 @@ static struct net_proto_family bt_sock_family_ops = { static int __init bt_init(void) { + int err; + BT_INFO("Core ver %s", VERSION); - sock_register(&bt_sock_family_ops); + err = bt_sysfs_init(); + if (err < 0) + return err; - BT_INFO("HCI device and connection manager initialized"); + err = sock_register(&bt_sock_family_ops); + if (err < 0) { + bt_sysfs_cleanup(); + return err; + } - bt_sysfs_init(); + BT_INFO("HCI device and connection manager initialized"); hci_sock_init(); @@ -325,9 +332,9 @@ static void __exit bt_exit(void) { hci_sock_cleanup(); - bt_sysfs_cleanup(); - sock_unregister(PF_BLUETOOTH); + + bt_sysfs_cleanup(); } subsys_initcall(bt_init); diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index d908d49dc9f8..2312d050eeed 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -29,7 +29,6 @@ * $Id: core.c,v 1.20 2002/08/04 21:23:58 maxk Exp $ */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -52,6 +51,7 @@ #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> #include <net/bluetooth/l2cap.h> #include "bnep.h" @@ -516,6 +516,26 @@ static int bnep_session(void *arg) return 0; } +static struct device *bnep_get_device(struct bnep_session *session) +{ + bdaddr_t *src = &bt_sk(session->sock->sk)->src; + bdaddr_t *dst = &bt_sk(session->sock->sk)->dst; + struct hci_dev *hdev; + struct hci_conn *conn; + + hdev = hci_get_route(dst, src); + if (!hdev) + return NULL; + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); + if (!conn) + return NULL; + + hci_dev_put(hdev); + + return &conn->dev; +} + int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) { struct net_device *dev; @@ -535,7 +555,6 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) if (!dev) return -ENOMEM; - down_write(&bnep_session_sem); ss = __bnep_get_session(dst); @@ -552,7 +571,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) memcpy(s->eh.h_source, &dst, ETH_ALEN); memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN); - s->dev = dev; + s->dev = dev; s->sock = sock; s->role = req->role; s->state = BT_CONNECTED; @@ -569,6 +588,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) bnep_set_default_proto_filter(s); #endif + SET_NETDEV_DEV(dev, bnep_get_device(s)); + err = register_netdev(dev); if (err) { goto failed; diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index 921204f95f4a..7f7b27db6a8f 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -29,7 +29,6 @@ * $Id: netdev.c,v 1.8 2002/08/04 21:23:58 maxk Exp $ */ -#include <linux/config.h> #include <linux/module.h> #include <linux/socket.h> diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 2bfe796cf05d..28c55835422a 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -28,7 +28,6 @@ * $Id: sock.c,v 1.4 2002/08/04 21:23:58 maxk Exp $ */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index b2e7e38531c6..be04e9fb11f6 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -20,7 +20,6 @@ SOFTWARE IS DISCLAIMED. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -76,15 +75,13 @@ static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl) { - struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL); + struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL); BT_DBG("session %p application %p appl %d", session, app, appl); if (!app) return NULL; - memset(app, 0, sizeof(*app)); - app->state = BT_OPEN; app->appl = appl; diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 901eff7ebe74..b81a01c64aea 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -20,7 +20,6 @@ SOFTWARE IS DISCLAIMED. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -336,10 +335,9 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) baswap(&src, &bt_sk(sock->sk)->src); baswap(&dst, &bt_sk(sock->sk)->dst); - session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL); + session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL); if (!session) return -ENOMEM; - memset(session, 0, sizeof(struct cmtp_session)); down_write(&cmtp_session_sem); diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 8f8fad23f78a..10ad7fd91d83 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -20,7 +20,6 @@ SOFTWARE IS DISCLAIMED. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index f812ed129e58..90e3a285a17e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -24,7 +24,6 @@ /* Bluetooth HCI connection handling. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -85,6 +84,20 @@ static void hci_acl_connect(struct hci_conn *conn) hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp); } +static void hci_acl_connect_cancel(struct hci_conn *conn) +{ + struct hci_cp_create_conn_cancel cp; + + BT_DBG("%p", conn); + + if (conn->hdev->hci_ver < 2) + return; + + bacpy(&cp.bdaddr, &conn->dst); + hci_send_cmd(conn->hdev, OGF_LINK_CTL, + OCF_CREATE_CONN_CANCEL, sizeof(cp), &cp); +} + void hci_acl_disconn(struct hci_conn *conn, __u8 reason) { struct hci_cp_disconnect cp; @@ -95,7 +108,8 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason) cp.handle = __cpu_to_le16(conn->handle); cp.reason = reason; - hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, sizeof(cp), &cp); + hci_send_cmd(conn->hdev, OGF_LINK_CTL, + OCF_DISCONNECT, sizeof(cp), &cp); } void hci_add_sco(struct hci_conn *conn, __u16 handle) @@ -116,8 +130,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) static void hci_conn_timeout(unsigned long arg) { - struct hci_conn *conn = (void *)arg; - struct hci_dev *hdev = conn->hdev; + struct hci_conn *conn = (void *) arg; + struct hci_dev *hdev = conn->hdev; BT_DBG("conn %p state %d", conn, conn->state); @@ -125,19 +139,29 @@ static void hci_conn_timeout(unsigned long arg) return; hci_dev_lock(hdev); - if (conn->state == BT_CONNECTED) + + switch (conn->state) { + case BT_CONNECT: + hci_acl_connect_cancel(conn); + break; + case BT_CONNECTED: hci_acl_disconn(conn, 0x13); - else + break; + default: conn->state = BT_CLOSED; + break; + } + hci_dev_unlock(hdev); - return; } -static void hci_conn_init_timer(struct hci_conn *conn) +static void hci_conn_idle(unsigned long arg) { - init_timer(&conn->timer); - conn->timer.function = hci_conn_timeout; - conn->timer.data = (unsigned long)conn; + struct hci_conn *conn = (void *) arg; + + BT_DBG("conn %p mode %d", conn, conn->mode); + + hci_conn_enter_sniff_mode(conn); } struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) @@ -146,17 +170,27 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) BT_DBG("%s dst %s", hdev->name, batostr(dst)); - if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC))) + conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC); + if (!conn) return NULL; - memset(conn, 0, sizeof(struct hci_conn)); bacpy(&conn->dst, dst); - conn->type = type; conn->hdev = hdev; + conn->type = type; + conn->mode = HCI_CM_ACTIVE; conn->state = BT_OPEN; + conn->power_save = 1; + skb_queue_head_init(&conn->data_q); - hci_conn_init_timer(conn); + + init_timer(&conn->disc_timer); + conn->disc_timer.function = hci_conn_timeout; + conn->disc_timer.data = (unsigned long) conn; + + init_timer(&conn->idle_timer); + conn->idle_timer.function = hci_conn_idle; + conn->idle_timer.data = (unsigned long) conn; atomic_set(&conn->refcnt, 0); @@ -168,6 +202,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); + hci_conn_add_sysfs(conn); + tasklet_enable(&hdev->tx_task); return conn; @@ -179,7 +215,9 @@ int hci_conn_del(struct hci_conn *conn) BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); - hci_conn_del_timer(conn); + del_timer(&conn->idle_timer); + + del_timer(&conn->disc_timer); if (conn->type == SCO_LINK) { struct hci_conn *acl = conn->link; @@ -198,6 +236,8 @@ int hci_conn_del(struct hci_conn *conn) tasklet_disable(&hdev->tx_task); + hci_conn_del_sysfs(conn); + hci_conn_hash_del(hdev, conn); if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); @@ -208,7 +248,9 @@ int hci_conn_del(struct hci_conn *conn) hci_dev_put(hdev); - kfree(conn); + /* will free via device release */ + put_device(&conn->dev); + return 0; } @@ -365,6 +407,70 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role) } EXPORT_SYMBOL(hci_conn_switch_role); +/* Enter active mode */ +void hci_conn_enter_active_mode(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + + BT_DBG("conn %p mode %d", conn, conn->mode); + + if (test_bit(HCI_RAW, &hdev->flags)) + return; + + if (conn->mode != HCI_CM_SNIFF || !conn->power_save) + goto timer; + + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + struct hci_cp_exit_sniff_mode cp; + cp.handle = __cpu_to_le16(conn->handle); + hci_send_cmd(hdev, OGF_LINK_POLICY, + OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp); + } + +timer: + if (hdev->idle_timeout > 0) + mod_timer(&conn->idle_timer, + jiffies + msecs_to_jiffies(hdev->idle_timeout)); +} + +/* Enter sniff mode */ +void hci_conn_enter_sniff_mode(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + + BT_DBG("conn %p mode %d", conn, conn->mode); + + if (test_bit(HCI_RAW, &hdev->flags)) + return; + + if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) + return; + + if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF)) + return; + + if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) { + struct hci_cp_sniff_subrate cp; + cp.handle = __cpu_to_le16(conn->handle); + cp.max_latency = __constant_cpu_to_le16(0); + cp.min_remote_timeout = __constant_cpu_to_le16(0); + cp.min_local_timeout = __constant_cpu_to_le16(0); + hci_send_cmd(hdev, OGF_LINK_POLICY, + OCF_SNIFF_SUBRATE, sizeof(cp), &cp); + } + + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + struct hci_cp_sniff_mode cp; + cp.handle = __cpu_to_le16(conn->handle); + cp.max_interval = __cpu_to_le16(hdev->sniff_max_interval); + cp.min_interval = __cpu_to_le16(hdev->sniff_min_interval); + cp.attempt = __constant_cpu_to_le16(4); + cp.timeout = __constant_cpu_to_le16(1); + hci_send_cmd(hdev, OGF_LINK_POLICY, + OCF_SNIFF_MODE, sizeof(cp), &cp); + } +} + /* Drop all connection on the device */ void hci_conn_hash_flush(struct hci_dev *hdev) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a49a6975092d..338ae977a31b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -24,7 +24,6 @@ /* Bluetooth HCI core. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kmod.h> @@ -207,6 +206,9 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) /* Read Local Supported Features */ hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL); + /* Read Local Version */ + hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL); + /* Read Buffer Size (ACL mtu, max pkt, etc.) */ hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL); @@ -337,9 +339,8 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) if (!(e = hci_inquiry_cache_lookup(hdev, &data->bdaddr))) { /* Entry not in the cache. Add new one. */ - if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) + if (!(e = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) return; - memset(e, 0, sizeof(struct inquiry_entry)); e->next = cache->list; cache->list = e; } @@ -412,7 +413,7 @@ int hci_inquiry(void __user *arg) } hci_dev_unlock_bh(hdev); - timeo = ir.length * 2 * HZ; + timeo = ir.length * msecs_to_jiffies(2000); if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) goto done; @@ -480,7 +481,8 @@ int hci_dev_open(__u16 dev) set_bit(HCI_INIT, &hdev->flags); //__hci_request(hdev, hci_reset_req, 0, HZ); - ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); + ret = __hci_request(hdev, hci_init_req, 0, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); clear_bit(HCI_INIT, &hdev->flags); } @@ -547,7 +549,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) atomic_set(&hdev->cmd_cnt, 1); if (!test_bit(HCI_RAW, &hdev->flags)) { set_bit(HCI_INIT, &hdev->flags); - __hci_request(hdev, hci_reset_req, 0, HZ/4); + __hci_request(hdev, hci_reset_req, 0, + msecs_to_jiffies(250)); clear_bit(HCI_INIT, &hdev->flags); } @@ -620,7 +623,8 @@ int hci_dev_reset(__u16 dev) hdev->acl_cnt = 0; hdev->sco_cnt = 0; if (!test_bit(HCI_RAW, &hdev->flags)) - ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); + ret = __hci_request(hdev, hci_reset_req, 0, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); done: tasklet_enable(&hdev->tx_task); @@ -658,7 +662,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) switch (cmd) { case HCISETAUTH: - err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT); + err = hci_request(hdev, hci_auth_req, dr.dev_opt, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETENCRYPT: @@ -669,18 +674,19 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) if (!test_bit(HCI_AUTH, &hdev->flags)) { /* Auth must be enabled first */ - err = hci_request(hdev, hci_auth_req, - dr.dev_opt, HCI_INIT_TIMEOUT); + err = hci_request(hdev, hci_auth_req, dr.dev_opt, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); if (err) break; } - err = hci_request(hdev, hci_encrypt_req, - dr.dev_opt, HCI_INIT_TIMEOUT); + err = hci_request(hdev, hci_encrypt_req, dr.dev_opt, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETSCAN: - err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); + err = hci_request(hdev, hci_scan_req, dr.dev_opt, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETPTYPE: @@ -796,12 +802,10 @@ struct hci_dev *hci_alloc_dev(void) { struct hci_dev *hdev; - hdev = kmalloc(sizeof(struct hci_dev), GFP_KERNEL); + hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); if (!hdev) return NULL; - memset(hdev, 0, sizeof(struct hci_dev)); - skb_queue_head_init(&hdev->driver_init); return hdev; @@ -813,8 +817,8 @@ void hci_free_dev(struct hci_dev *hdev) { skb_queue_purge(&hdev->driver_init); - /* will free via class release */ - class_device_put(&hdev->class_dev); + /* will free via device release */ + put_device(&hdev->dev); } EXPORT_SYMBOL(hci_free_dev); @@ -849,6 +853,10 @@ int hci_register_dev(struct hci_dev *hdev) hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); hdev->link_mode = (HCI_LM_ACCEPT); + hdev->idle_timeout = 0; + hdev->sniff_max_interval = 800; + hdev->sniff_min_interval = 80; + tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); @@ -1221,6 +1229,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev) while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); + + hci_conn_enter_active_mode(conn); + hci_send_frame(skb); hdev->acl_last_tx = jiffies; @@ -1299,6 +1310,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) if (conn) { register struct hci_proto *hp; + hci_conn_enter_active_mode(conn); + /* Send to upper protocol */ if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) { hp->recv_acldata(conn, skb, flags); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index eb64555d1fb3..d43d0c890975 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -24,7 +24,6 @@ /* Bluetooth HCI event handling. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -63,6 +62,7 @@ static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb switch (ocf) { case OCF_INQUIRY_CANCEL: + case OCF_EXIT_PERIODIC_INQ: status = *((__u8 *) skb->data); if (status) { @@ -84,6 +84,8 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff * { struct hci_conn *conn; struct hci_rp_role_discovery *rd; + struct hci_rp_write_link_policy *lp; + void *sent; BT_DBG("%s ocf 0x%x", hdev->name, ocf); @@ -107,6 +109,27 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff * hci_dev_unlock(hdev); break; + case OCF_WRITE_LINK_POLICY: + sent = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY); + if (!sent) + break; + + lp = (struct hci_rp_write_link_policy *) skb->data; + + if (lp->status) + break; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(lp->handle)); + if (conn) { + __le16 policy = get_unaligned((__le16 *) (sent + 2)); + conn->link_policy = __le16_to_cpu(policy); + } + + hci_dev_unlock(hdev); + break; + default: BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf); @@ -275,15 +298,33 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb /* Command Complete OGF INFO_PARAM */ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) { - struct hci_rp_read_loc_features *lf; + struct hci_rp_read_loc_version *lv; + struct hci_rp_read_local_features *lf; struct hci_rp_read_buffer_size *bs; struct hci_rp_read_bd_addr *ba; BT_DBG("%s ocf 0x%x", hdev->name, ocf); switch (ocf) { + case OCF_READ_LOCAL_VERSION: + lv = (struct hci_rp_read_loc_version *) skb->data; + + if (lv->status) { + BT_DBG("%s READ_LOCAL_VERSION failed %d", hdev->name, lf->status); + break; + } + + hdev->hci_ver = lv->hci_ver; + hdev->hci_rev = btohs(lv->hci_rev); + hdev->manufacturer = btohs(lv->manufacturer); + + BT_DBG("%s: manufacturer %d hci_ver %d hci_rev %d", hdev->name, + hdev->manufacturer, hdev->hci_ver, hdev->hci_rev); + + break; + case OCF_READ_LOCAL_FEATURES: - lf = (struct hci_rp_read_loc_features *) skb->data; + lf = (struct hci_rp_read_local_features *) skb->data; if (lf->status) { BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); @@ -306,7 +347,8 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s if (hdev->features[1] & LMP_HV3) hdev->pkt_type |= (HCI_HV3); - BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]); + BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, + lf->features[0], lf->features[1], lf->features[2]); break; @@ -320,9 +362,17 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s } hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); - hdev->sco_mtu = bs->sco_mtu ? bs->sco_mtu : 64; - hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt); - hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); + hdev->sco_mtu = bs->sco_mtu; + hdev->acl_pkts = __le16_to_cpu(bs->acl_max_pkt); + hdev->sco_pkts = __le16_to_cpu(bs->sco_max_pkt); + + if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) { + hdev->sco_mtu = 64; + hdev->sco_pkts = 8; + } + + hdev->acl_cnt = hdev->acl_pkts; + hdev->sco_cnt = hdev->sco_pkts; BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts); @@ -440,8 +490,46 @@ static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) BT_DBG("%s ocf 0x%x", hdev->name, ocf); switch (ocf) { + case OCF_SNIFF_MODE: + if (status) { + struct hci_conn *conn; + struct hci_cp_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_SNIFF_MODE); + + if (!cp) + break; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) { + clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); + } + + hci_dev_unlock(hdev); + } + break; + + case OCF_EXIT_SNIFF_MODE: + if (status) { + struct hci_conn *conn; + struct hci_cp_exit_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_EXIT_SNIFF_MODE); + + if (!cp) + break; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) { + clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); + } + + hci_dev_unlock(hdev); + } + break; + default: - BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf); + BT_DBG("%s Command status: ogf LINK_POLICY ocf %x", hdev->name, ocf); break; } } @@ -623,14 +711,16 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk else cp.role = 0x01; /* Remain slave */ - hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp); + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp); } else { /* Connection rejected */ struct hci_cp_reject_conn_req cp; bacpy(&cp.bdaddr, &ev->bdaddr); cp.reason = 0x0f; - hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ, sizeof(cp), &cp); + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_REJECT_CONN_REQ, sizeof(cp), &cp); } } @@ -638,7 +728,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data; - struct hci_conn *conn = NULL; + struct hci_conn *conn; BT_DBG("%s", hdev->name); @@ -660,12 +750,21 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (test_bit(HCI_ENCRYPT, &hdev->flags)) conn->link_mode |= HCI_LM_ENCRYPT; + /* Get remote features */ + if (conn->type == ACL_LINK) { + struct hci_cp_read_remote_features cp; + cp.handle = ev->handle; + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_READ_REMOTE_FEATURES, sizeof(cp), &cp); + } + /* Set link policy */ if (conn->type == ACL_LINK && hdev->link_policy) { struct hci_cp_write_link_policy cp; cp.handle = ev->handle; cp.policy = __cpu_to_le16(hdev->link_policy); - hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, sizeof(cp), &cp); + hci_send_cmd(hdev, OGF_LINK_POLICY, + OCF_WRITE_LINK_POLICY, sizeof(cp), &cp); } /* Set packet type for incoming connection */ @@ -676,7 +775,12 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); - hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp); + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp); + } else { + /* Update disconnect timer */ + hci_conn_hold(conn); + hci_conn_put(conn); } } else conn->state = BT_CLOSED; @@ -704,8 +808,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data; - struct hci_conn *conn = NULL; - __u16 handle = __le16_to_cpu(ev->handle); + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); @@ -714,7 +817,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_handle(hdev, handle); + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { conn->state = BT_CLOSED; hci_proto_disconn_ind(conn, ev->reason); @@ -771,7 +874,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_role_change *ev = (struct hci_ev_role_change *) skb->data; - struct hci_conn *conn = NULL; + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); @@ -794,18 +897,43 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_unlock(hdev); } +/* Mode Change */ +static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_mode_change *ev = (struct hci_ev_mode_change *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status %d", hdev->name, ev->status); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn) { + conn->mode = ev->mode; + conn->interval = __le16_to_cpu(ev->interval); + + if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + if (conn->mode == HCI_CM_ACTIVE) + conn->power_save = 1; + else + conn->power_save = 0; + } + } + + hci_dev_unlock(hdev); +} + /* Authentication Complete */ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data; - struct hci_conn *conn = NULL; - __u16 handle = __le16_to_cpu(ev->handle); + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_handle(hdev, handle); + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) conn->link_mode |= HCI_LM_AUTH; @@ -820,8 +948,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s cp.handle = __cpu_to_le16(conn->handle); cp.encrypt = 1; hci_send_cmd(conn->hdev, OGF_LINK_CTL, - OCF_SET_CONN_ENCRYPT, - sizeof(cp), &cp); + OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp); } else { clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); hci_encrypt_cfm(conn, ev->status, 0x00); @@ -836,14 +963,13 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) skb->data; - struct hci_conn *conn = NULL; - __u16 handle = __le16_to_cpu(ev->handle); + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_handle(hdev, handle); + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) { if (ev->encrypt) @@ -864,14 +990,13 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data; - struct hci_conn *conn = NULL; - __u16 handle = __le16_to_cpu(ev->handle); + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_handle(hdev, handle); + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) conn->link_mode |= HCI_LM_SECURE; @@ -899,18 +1024,35 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff { } +/* Remote Features */ +static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_remote_features *ev = (struct hci_ev_remote_features *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status %d", hdev->name, ev->status); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn && !ev->status) { + memcpy(conn->features, ev->features, sizeof(conn->features)); + } + + hci_dev_unlock(hdev); +} + /* Clock Offset */ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) skb->data; - struct hci_conn *conn = NULL; - __u16 handle = __le16_to_cpu(ev->handle); + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_handle(hdev, handle); + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn && !ev->status) { struct inquiry_entry *ie; @@ -941,6 +1083,23 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_unlock(hdev); } +/* Sniff Subrate */ +static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_sniff_subrate *ev = (struct hci_ev_sniff_subrate *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status %d", hdev->name, ev->status); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn) { + } + + hci_dev_unlock(hdev); +} + void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data; @@ -989,6 +1148,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_role_change_evt(hdev, skb); break; + case HCI_EV_MODE_CHANGE: + hci_mode_change_evt(hdev, skb); + break; + case HCI_EV_AUTH_COMPLETE: hci_auth_complete_evt(hdev, skb); break; @@ -1013,6 +1176,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_link_key_notify_evt(hdev, skb); break; + case HCI_EV_REMOTE_FEATURES: + hci_remote_features_evt(hdev, skb); + break; + case HCI_EV_CLOCK_OFFSET: hci_clock_offset_evt(hdev, skb); break; @@ -1021,6 +1188,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_pscan_rep_mode_evt(hdev, skb); break; + case HCI_EV_SNIFF_SUBRATE: + hci_sniff_subrate_evt(hdev, skb); + break; + case HCI_EV_CMD_STATUS: cs = (struct hci_ev_cmd_status *) skb->data; skb_pull(skb, sizeof(cs)); diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 97bdec73d17e..1a35d343e08a 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -24,7 +24,6 @@ /* Bluetooth HCI sockets. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 0ed38740388c..989b22d9042e 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -1,9 +1,10 @@ /* Bluetooth HCI driver model support. */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/platform_device.h> + #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -12,35 +13,63 @@ #define BT_DBG(D...) #endif -static ssize_t show_name(struct class_device *cdev, char *buf) +static inline char *typetostr(int type) { - struct hci_dev *hdev = class_get_devdata(cdev); - return sprintf(buf, "%s\n", hdev->name); + switch (type) { + case HCI_VIRTUAL: + return "VIRTUAL"; + case HCI_USB: + return "USB"; + case HCI_PCCARD: + return "PCCARD"; + case HCI_UART: + return "UART"; + case HCI_RS232: + return "RS232"; + case HCI_PCI: + return "PCI"; + case HCI_SDIO: + return "SDIO"; + default: + return "UNKNOWN"; + } } -static ssize_t show_type(struct class_device *cdev, char *buf) +static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); - return sprintf(buf, "%d\n", hdev->type); + struct hci_dev *hdev = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", typetostr(hdev->type)); } -static ssize_t show_address(struct class_device *cdev, char *buf) +static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); bdaddr_t bdaddr; baswap(&bdaddr, &hdev->bdaddr); return sprintf(buf, "%s\n", batostr(&bdaddr)); } -static ssize_t show_flags(struct class_device *cdev, char *buf) +static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hci_dev *hdev = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", hdev->manufacturer); +} + +static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hci_dev *hdev = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", hdev->hci_ver); +} + +static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); - return sprintf(buf, "0x%lx\n", hdev->flags); + struct hci_dev *hdev = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", hdev->hci_rev); } -static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf) +static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_entry *e; int n = 0; @@ -62,94 +91,268 @@ static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf) return n; } -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); -static CLASS_DEVICE_ATTR(type, S_IRUGO, show_type, NULL); -static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL); -static CLASS_DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); -static CLASS_DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL); +static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hci_dev *hdev = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", hdev->idle_timeout); +} -static struct class_device_attribute *bt_attrs[] = { - &class_device_attr_name, - &class_device_attr_type, - &class_device_attr_address, - &class_device_attr_flags, - &class_device_attr_inquiry_cache, - NULL -}; +static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct hci_dev *hdev = dev_get_drvdata(dev); + char *ptr; + __u32 val; + + val = simple_strtoul(buf, &ptr, 10); + if (ptr == buf) + return -EINVAL; + + if (val != 0 && (val < 500 || val > 3600000)) + return -EINVAL; + + hdev->idle_timeout = val; + + return count; +} -#ifdef CONFIG_HOTPLUG -static int bt_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size) +static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); - int n, i = 0; + struct hci_dev *hdev = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", hdev->sniff_max_interval); +} - envp[i++] = buf; - n = snprintf(buf, size, "INTERFACE=%s", hdev->name) + 1; - buf += n; - size -= n; +static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct hci_dev *hdev = dev_get_drvdata(dev); + char *ptr; + __u16 val; - if ((size <= 0) || (i >= num_envp)) - return -ENOMEM; + val = simple_strtoul(buf, &ptr, 10); + if (ptr == buf) + return -EINVAL; - envp[i] = NULL; - return 0; + if (val < 0x0002 || val > 0xFFFE || val % 2) + return -EINVAL; + + if (val < hdev->sniff_min_interval) + return -EINVAL; + + hdev->sniff_max_interval = val; + + return count; +} + +static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hci_dev *hdev = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", hdev->sniff_min_interval); } -#endif -static void bt_release(struct class_device *cdev) +static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); + char *ptr; + __u16 val; + + val = simple_strtoul(buf, &ptr, 10); + if (ptr == buf) + return -EINVAL; - kfree(hdev); + if (val < 0x0002 || val > 0xFFFE || val % 2) + return -EINVAL; + + if (val > hdev->sniff_max_interval) + return -EINVAL; + + hdev->sniff_min_interval = val; + + return count; } -struct class bt_class = { - .name = "bluetooth", - .release = bt_release, -#ifdef CONFIG_HOTPLUG - .uevent = bt_uevent, -#endif +static DEVICE_ATTR(type, S_IRUGO, show_type, NULL); +static DEVICE_ATTR(address, S_IRUGO, show_address, NULL); +static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL); +static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL); +static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL); +static DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL); + +static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR, + show_idle_timeout, store_idle_timeout); +static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR, + show_sniff_max_interval, store_sniff_max_interval); +static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR, + show_sniff_min_interval, store_sniff_min_interval); + +static struct device_attribute *bt_attrs[] = { + &dev_attr_type, + &dev_attr_address, + &dev_attr_manufacturer, + &dev_attr_hci_version, + &dev_attr_hci_revision, + &dev_attr_inquiry_cache, + &dev_attr_idle_timeout, + &dev_attr_sniff_max_interval, + &dev_attr_sniff_min_interval, + NULL }; +static ssize_t show_conn_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hci_conn *conn = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", conn->type == ACL_LINK ? "ACL" : "SCO"); +} + +static ssize_t show_conn_address(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hci_conn *conn = dev_get_drvdata(dev); + bdaddr_t bdaddr; + baswap(&bdaddr, &conn->dst); + return sprintf(buf, "%s\n", batostr(&bdaddr)); +} + +#define CONN_ATTR(_name,_mode,_show,_store) \ +struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store) + +static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL); +static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL); + +static struct device_attribute *conn_attrs[] = { + &conn_attr_type, + &conn_attr_address, + NULL +}; + +struct class *bt_class = NULL; EXPORT_SYMBOL_GPL(bt_class); +static struct bus_type bt_bus = { + .name = "bluetooth", +}; + +static struct platform_device *bt_platform; + +static void bt_release(struct device *dev) +{ + void *data = dev_get_drvdata(dev); + kfree(data); +} + +static void add_conn(void *data) +{ + struct hci_conn *conn = data; + int i; + + device_register(&conn->dev); + + for (i = 0; conn_attrs[i]; i++) + device_create_file(&conn->dev, conn_attrs[i]); +} + +void hci_conn_add_sysfs(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + bdaddr_t *ba = &conn->dst; + + BT_DBG("conn %p", conn); + + conn->dev.parent = &hdev->dev; + conn->dev.release = bt_release; + + snprintf(conn->dev.bus_id, BUS_ID_SIZE, + "%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", + conn->type == ACL_LINK ? "acl" : "sco", + ba->b[5], ba->b[4], ba->b[3], + ba->b[2], ba->b[1], ba->b[0]); + + dev_set_drvdata(&conn->dev, conn); + + INIT_WORK(&conn->work, add_conn, (void *) conn); + + schedule_work(&conn->work); +} + +static void del_conn(void *data) +{ + struct hci_conn *conn = data; + device_del(&conn->dev); +} + +void hci_conn_del_sysfs(struct hci_conn *conn) +{ + BT_DBG("conn %p", conn); + + INIT_WORK(&conn->work, del_conn, (void *) conn); + + schedule_work(&conn->work); +} + int hci_register_sysfs(struct hci_dev *hdev) { - struct class_device *cdev = &hdev->class_dev; + struct device *dev = &hdev->dev; unsigned int i; int err; BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - cdev->class = &bt_class; - class_set_devdata(cdev, hdev); + dev->class = bt_class; - strlcpy(cdev->class_id, hdev->name, BUS_ID_SIZE); - err = class_device_register(cdev); + if (hdev->parent) + dev->parent = hdev->parent; + else + dev->parent = &bt_platform->dev; + + strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE); + + dev->release = bt_release; + + dev_set_drvdata(dev, hdev); + + err = device_register(dev); if (err < 0) return err; for (i = 0; bt_attrs[i]; i++) - class_device_create_file(cdev, bt_attrs[i]); + device_create_file(dev, bt_attrs[i]); return 0; } void hci_unregister_sysfs(struct hci_dev *hdev) { - struct class_device * cdev = &hdev->class_dev; - BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - class_device_del(cdev); + device_del(&hdev->dev); } int __init bt_sysfs_init(void) { - return class_register(&bt_class); + int err; + + bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0); + if (IS_ERR(bt_platform)) + return PTR_ERR(bt_platform); + + err = bus_register(&bt_bus); + if (err < 0) { + platform_device_unregister(bt_platform); + return err; + } + + bt_class = class_create(THIS_MODULE, "bluetooth"); + if (IS_ERR(bt_class)) { + bus_unregister(&bt_bus); + platform_device_unregister(bt_platform); + return PTR_ERR(bt_class); + } + + return 0; } -void __exit bt_sysfs_cleanup(void) +void bt_sysfs_cleanup(void) { - class_unregister(&bt_class); + class_destroy(bt_class); + + bus_unregister(&bt_bus); + + platform_device_unregister(bt_platform); } diff --git a/net/bluetooth/hidp/Kconfig b/net/bluetooth/hidp/Kconfig index edfea772fb67..c6abf2a5a932 100644 --- a/net/bluetooth/hidp/Kconfig +++ b/net/bluetooth/hidp/Kconfig @@ -1,7 +1,6 @@ config BT_HIDP tristate "HIDP protocol support" - depends on BT && BT_L2CAP && (BROKEN || !S390) - select INPUT + depends on BT && BT_L2CAP && INPUT help HIDP (Human Interface Device Protocol) is a transport layer for HID reports. HIDP is required for the Bluetooth Human diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index cdb9cfafd960..03b5dadb4951 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -20,7 +20,6 @@ SOFTWARE IS DISCLAIMED. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -41,6 +40,7 @@ #include <linux/input.h> #include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> #include <net/bluetooth/l2cap.h> #include "hidp.h" @@ -529,6 +529,26 @@ static int hidp_session(void *arg) return 0; } +static struct device *hidp_get_device(struct hidp_session *session) +{ + bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src; + bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst; + struct hci_dev *hdev; + struct hci_conn *conn; + + hdev = hci_get_route(dst, src); + if (!hdev) + return NULL; + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); + if (!conn) + return NULL; + + hci_dev_put(hdev); + + return &conn->dev; +} + static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req) { struct input_dev *input = session->input; @@ -567,6 +587,8 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co input->relbit[0] |= BIT(REL_WHEEL); } + input->cdev.dev = hidp_get_device(session); + input->event = hidp_input_event; input_register_device(input); @@ -583,10 +605,9 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst)) return -ENOTUNIQ; - session = kmalloc(sizeof(struct hidp_session), GFP_KERNEL); + session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL); if (!session) return -ENOMEM; - memset(session, 0, sizeof(struct hidp_session)); session->input = input_allocate_device(); if (!session->input) { diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index b8f67761b886..099646e4e2ef 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -20,7 +20,6 @@ SOFTWARE IS DISCLAIMED. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index f6b4a8085357..d56f60b392ac 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -24,7 +24,6 @@ /* Bluetooth L2CAP core and sockets. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -64,11 +63,6 @@ static struct bt_sock_list l2cap_sk_list = { .lock = RW_LOCK_UNLOCKED }; -static int l2cap_conn_del(struct hci_conn *conn, int err); - -static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent); -static void l2cap_chan_del(struct sock *sk, int err); - static void __l2cap_sock_close(struct sock *sk, int reason); static void l2cap_sock_close(struct sock *sk); static void l2cap_sock_kill(struct sock *sk); @@ -110,24 +104,177 @@ static void l2cap_sock_init_timer(struct sock *sk) sk->sk_timer.data = (unsigned long)sk; } +/* ---- L2CAP channels ---- */ +static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) +{ + struct sock *s; + for (s = l->head; s; s = l2cap_pi(s)->next_c) { + if (l2cap_pi(s)->dcid == cid) + break; + } + return s; +} + +static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +{ + struct sock *s; + for (s = l->head; s; s = l2cap_pi(s)->next_c) { + if (l2cap_pi(s)->scid == cid) + break; + } + return s; +} + +/* Find channel with given SCID. + * Returns locked socket */ +static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +{ + struct sock *s; + read_lock(&l->lock); + s = __l2cap_get_chan_by_scid(l, cid); + if (s) bh_lock_sock(s); + read_unlock(&l->lock); + return s; +} + +static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +{ + struct sock *s; + for (s = l->head; s; s = l2cap_pi(s)->next_c) { + if (l2cap_pi(s)->ident == ident) + break; + } + return s; +} + +static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +{ + struct sock *s; + read_lock(&l->lock); + s = __l2cap_get_chan_by_ident(l, ident); + if (s) bh_lock_sock(s); + read_unlock(&l->lock); + return s; +} + +static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) +{ + u16 cid = 0x0040; + + for (; cid < 0xffff; cid++) { + if(!__l2cap_get_chan_by_scid(l, cid)) + return cid; + } + + return 0; +} + +static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) +{ + sock_hold(sk); + + if (l->head) + l2cap_pi(l->head)->prev_c = sk; + + l2cap_pi(sk)->next_c = l->head; + l2cap_pi(sk)->prev_c = NULL; + l->head = sk; +} + +static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) +{ + struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; + + write_lock_bh(&l->lock); + if (sk == l->head) + l->head = next; + + if (next) + l2cap_pi(next)->prev_c = prev; + if (prev) + l2cap_pi(prev)->next_c = next; + write_unlock_bh(&l->lock); + + __sock_put(sk); +} + +static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +{ + struct l2cap_chan_list *l = &conn->chan_list; + + BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); + + l2cap_pi(sk)->conn = conn; + + if (sk->sk_type == SOCK_SEQPACKET) { + /* Alloc CID for connection-oriented socket */ + l2cap_pi(sk)->scid = l2cap_alloc_cid(l); + } else if (sk->sk_type == SOCK_DGRAM) { + /* Connectionless socket */ + l2cap_pi(sk)->scid = 0x0002; + l2cap_pi(sk)->dcid = 0x0002; + l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + } else { + /* Raw socket can send/recv signalling messages only */ + l2cap_pi(sk)->scid = 0x0001; + l2cap_pi(sk)->dcid = 0x0001; + l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + } + + __l2cap_chan_link(l, sk); + + if (parent) + bt_accept_enqueue(parent, sk); +} + +/* Delete channel. + * Must be called on the locked socket. */ +static void l2cap_chan_del(struct sock *sk, int err) +{ + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sock *parent = bt_sk(sk)->parent; + + l2cap_sock_clear_timer(sk); + + BT_DBG("sk %p, conn %p, err %d", sk, conn, err); + + if (conn) { + /* Unlink from channel list */ + l2cap_chan_unlink(&conn->chan_list, sk); + l2cap_pi(sk)->conn = NULL; + hci_conn_put(conn->hcon); + } + + sk->sk_state = BT_CLOSED; + sock_set_flag(sk, SOCK_ZAPPED); + + if (err) + sk->sk_err = err; + + if (parent) { + bt_accept_unlink(sk); + parent->sk_data_ready(parent, 0); + } else + sk->sk_state_change(sk); +} + /* ---- L2CAP connections ---- */ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) { - struct l2cap_conn *conn; - - if ((conn = hcon->l2cap_data)) - return conn; + struct l2cap_conn *conn = hcon->l2cap_data; - if (status) + if (conn || status) return conn; - if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC))) + conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC); + if (!conn) return NULL; - memset(conn, 0, sizeof(struct l2cap_conn)); hcon->l2cap_data = conn; conn->hcon = hcon; + BT_DBG("hcon %p conn %p", hcon, conn); + conn->mtu = hcon->hdev->acl_mtu; conn->src = &hcon->hdev->bdaddr; conn->dst = &hcon->dst; @@ -135,17 +282,16 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) spin_lock_init(&conn->lock); rwlock_init(&conn->chan_list.lock); - BT_DBG("hcon %p conn %p", hcon, conn); return conn; } -static int l2cap_conn_del(struct hci_conn *hcon, int err) +static void l2cap_conn_del(struct hci_conn *hcon, int err) { - struct l2cap_conn *conn; + struct l2cap_conn *conn = hcon->l2cap_data; struct sock *sk; - if (!(conn = hcon->l2cap_data)) - return 0; + if (!conn) + return; BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); @@ -162,15 +308,14 @@ static int l2cap_conn_del(struct hci_conn *hcon, int err) hcon->l2cap_data = NULL; kfree(conn); - return 0; } static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) { struct l2cap_chan_list *l = &conn->chan_list; - write_lock(&l->lock); + write_lock_bh(&l->lock); __l2cap_chan_add(conn, sk, parent); - write_unlock(&l->lock); + write_unlock_bh(&l->lock); } static inline u8 l2cap_get_ident(struct l2cap_conn *conn) @@ -183,14 +328,14 @@ static inline u8 l2cap_get_ident(struct l2cap_conn *conn) * 200 - 254 are used by utilities like l2ping, etc. */ - spin_lock(&conn->lock); + spin_lock_bh(&conn->lock); if (++conn->tx_ident > 128) conn->tx_ident = 1; id = conn->tx_ident; - spin_unlock(&conn->lock); + spin_unlock_bh(&conn->lock); return id; } @@ -926,160 +1071,6 @@ static int l2cap_sock_release(struct socket *sock) return err; } -/* ---- L2CAP channels ---- */ -static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) -{ - struct sock *s; - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->dcid == cid) - break; - } - return s; -} - -static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) -{ - struct sock *s; - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->scid == cid) - break; - } - return s; -} - -/* Find channel with given SCID. - * Returns locked socket */ -static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) -{ - struct sock *s; - read_lock(&l->lock); - s = __l2cap_get_chan_by_scid(l, cid); - if (s) bh_lock_sock(s); - read_unlock(&l->lock); - return s; -} - -static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) -{ - struct sock *s; - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->ident == ident) - break; - } - return s; -} - -static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) -{ - struct sock *s; - read_lock(&l->lock); - s = __l2cap_get_chan_by_ident(l, ident); - if (s) bh_lock_sock(s); - read_unlock(&l->lock); - return s; -} - -static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) -{ - u16 cid = 0x0040; - - for (; cid < 0xffff; cid++) { - if(!__l2cap_get_chan_by_scid(l, cid)) - return cid; - } - - return 0; -} - -static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) -{ - sock_hold(sk); - - if (l->head) - l2cap_pi(l->head)->prev_c = sk; - - l2cap_pi(sk)->next_c = l->head; - l2cap_pi(sk)->prev_c = NULL; - l->head = sk; -} - -static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) -{ - struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; - - write_lock(&l->lock); - if (sk == l->head) - l->head = next; - - if (next) - l2cap_pi(next)->prev_c = prev; - if (prev) - l2cap_pi(prev)->next_c = next; - write_unlock(&l->lock); - - __sock_put(sk); -} - -static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) -{ - struct l2cap_chan_list *l = &conn->chan_list; - - BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); - - l2cap_pi(sk)->conn = conn; - - if (sk->sk_type == SOCK_SEQPACKET) { - /* Alloc CID for connection-oriented socket */ - l2cap_pi(sk)->scid = l2cap_alloc_cid(l); - } else if (sk->sk_type == SOCK_DGRAM) { - /* Connectionless socket */ - l2cap_pi(sk)->scid = 0x0002; - l2cap_pi(sk)->dcid = 0x0002; - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; - } else { - /* Raw socket can send/recv signalling messages only */ - l2cap_pi(sk)->scid = 0x0001; - l2cap_pi(sk)->dcid = 0x0001; - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; - } - - __l2cap_chan_link(l, sk); - - if (parent) - bt_accept_enqueue(parent, sk); -} - -/* Delete channel. - * Must be called on the locked socket. */ -static void l2cap_chan_del(struct sock *sk, int err) -{ - struct l2cap_conn *conn = l2cap_pi(sk)->conn; - struct sock *parent = bt_sk(sk)->parent; - - l2cap_sock_clear_timer(sk); - - BT_DBG("sk %p, conn %p, err %d", sk, conn, err); - - if (conn) { - /* Unlink from channel list */ - l2cap_chan_unlink(&conn->chan_list, sk); - l2cap_pi(sk)->conn = NULL; - hci_conn_put(conn->hcon); - } - - sk->sk_state = BT_CLOSED; - sock_set_flag(sk, SOCK_ZAPPED); - - if (err) - sk->sk_err = err; - - if (parent) { - bt_accept_unlink(sk); - parent->sk_data_ready(parent, 0); - } else - sk->sk_state_change(sk); -} - static void l2cap_conn_ready(struct l2cap_conn *conn) { struct l2cap_chan_list *l = &conn->chan_list; @@ -1425,11 +1416,11 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd if (!sk) goto response; - write_lock(&list->lock); + write_lock_bh(&list->lock); /* Check if we already have channel with that dcid */ if (__l2cap_get_chan_by_dcid(list, scid)) { - write_unlock(&list->lock); + write_unlock_bh(&list->lock); sock_set_flag(sk, SOCK_ZAPPED); l2cap_sock_kill(sk); goto response; @@ -1467,7 +1458,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd result = status = 0; done: - write_unlock(&list->lock); + write_unlock_bh(&list->lock); response: bh_unlock_sock(parent); @@ -1835,7 +1826,9 @@ drop: kfree_skb(skb); done: - if (sk) bh_unlock_sock(sk); + if (sk) + bh_unlock_sock(sk); + return 0; } @@ -1926,18 +1919,18 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) { + struct l2cap_conn *conn; + BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); if (hcon->type != ACL_LINK) return 0; if (!status) { - struct l2cap_conn *conn; - conn = l2cap_conn_add(hcon, status); if (conn) l2cap_conn_ready(conn); - } else + } else l2cap_conn_del(hcon, bt_err(status)); return 0; @@ -1951,19 +1944,21 @@ static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason) return 0; l2cap_conn_del(hcon, bt_err(reason)); + return 0; } static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status) { struct l2cap_chan_list *l; - struct l2cap_conn *conn; + struct l2cap_conn *conn = conn = hcon->l2cap_data; struct l2cap_conn_rsp rsp; struct sock *sk; int result; - if (!(conn = hcon->l2cap_data)) + if (!conn) return 0; + l = &conn->chan_list; BT_DBG("conn %p", conn); @@ -2006,13 +2001,14 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status) static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status) { struct l2cap_chan_list *l; - struct l2cap_conn *conn; + struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_conn_rsp rsp; struct sock *sk; int result; - if (!(conn = hcon->l2cap_data)) + if (!conn) return 0; + l = &conn->chan_list; BT_DBG("conn %p", conn); @@ -2220,7 +2216,7 @@ static int __init l2cap_init(void) goto error; } - class_create_file(&bt_class, &class_attr_l2cap); + class_create_file(bt_class, &class_attr_l2cap); BT_INFO("L2CAP ver %s", VERSION); BT_INFO("L2CAP socket layer initialized"); @@ -2234,7 +2230,7 @@ error: static void __exit l2cap_exit(void) { - class_remove_file(&bt_class, &class_attr_l2cap); + class_remove_file(bt_class, &class_attr_l2cap); if (bt_sock_unregister(BTPROTO_L2CAP) < 0) BT_ERR("L2CAP socket unregistration failed"); diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index ee6a66979913..e5fd0cb70ae9 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -24,7 +24,6 @@ /* Bluetooth kernel library. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> 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); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 0c2d13ad69bb..7714a2ec3854 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -24,7 +24,6 @@ /* Bluetooth SCO sockets. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -109,17 +108,14 @@ static void sco_sock_init_timer(struct sock *sk) static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status) { struct hci_dev *hdev = hcon->hdev; - struct sco_conn *conn; - - if ((conn = hcon->sco_data)) - return conn; + struct sco_conn *conn = hcon->sco_data; - if (status) + if (conn || status) return conn; - if (!(conn = kmalloc(sizeof(struct sco_conn), GFP_ATOMIC))) + conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC); + if (!conn) return NULL; - memset(conn, 0, sizeof(struct sco_conn)); spin_lock_init(&conn->lock); @@ -135,6 +131,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status) conn->mtu = 60; BT_DBG("hcon %p conn %p", hcon, conn); + return conn; } @@ -970,7 +967,7 @@ static int __init sco_init(void) goto error; } - class_create_file(&bt_class, &class_attr_sco); + class_create_file(bt_class, &class_attr_sco); BT_INFO("SCO (Voice Link) ver %s", VERSION); BT_INFO("SCO socket layer initialized"); @@ -984,7 +981,7 @@ error: static void __exit sco_exit(void) { - class_remove_file(&bt_class, &class_attr_sco); + class_remove_file(bt_class, &class_attr_sco); if (bt_sock_unregister(BTPROTO_SCO) < 0) BT_ERR("SCO socket unregistration failed"); |