From b3cf652afb5404685e3d7ed6780a8d1fa10e21da Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Mon, 28 Sep 2009 19:43:35 -0700 Subject: Bluetooth: Removal of unused variable in btmrvl driver This patch removes unused variable "drvdbg" from btmrvl_debugfs_data structure. Signed-off-by: Rahul Tank Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_debugfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index 4617bd12f63b..d43b5cb864ef 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -29,7 +29,6 @@ struct btmrvl_debugfs_data { struct dentry *root_dir, *config_dir, *status_dir; /* config */ - struct dentry *drvdbg; struct dentry *psmode; struct dentry *pscmd; struct dentry *hsmode; -- cgit v1.2.3 From 5990108cfcd3eb2d365c9ea6f82318be80c4e9d3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Oct 2009 20:28:53 +0000 Subject: Bluetooth: Remove stub ioctl in hci_vhci Remove the empty ioctl which just returns -EINVAL. vfs_ioctl() will return -ENOTTY instead, but I doubt that any application will notice the difference :) Signed-off-by: Thomas Gleixner Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_vhci.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index d5cde6d86f89..ff02e901ab83 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -218,12 +218,6 @@ static unsigned int vhci_poll(struct file *file, poll_table *wait) return POLLOUT | POLLWRNORM; } -static int vhci_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return -EINVAL; -} - static int vhci_open(struct inode *inode, struct file *file) { struct vhci_data *data; @@ -287,7 +281,6 @@ static const struct file_operations vhci_fops = { .read = vhci_read, .write = vhci_write, .poll = vhci_poll, - .ioctl = vhci_ioctl, .open = vhci_open, .release = vhci_release, }; -- cgit v1.2.3 From 329ab1b3e6ceac3f77ab400206a97cc402624259 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 3 Dec 2009 18:05:16 +0100 Subject: Bluetooth: Remove unused global minor variable After the removal of the module parameter for setting the minor number, this variable became unused. So just remove it. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_vhci.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index ff02e901ab83..c1d389f2cbaf 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -41,8 +41,6 @@ #define VERSION "1.3" -static int minor = MISC_DYNAMIC_MINOR; - struct vhci_data { struct hci_dev *hdev; @@ -295,18 +293,12 @@ static int __init vhci_init(void) { BT_INFO("Virtual HCI driver ver %s", VERSION); - if (misc_register(&vhci_miscdev) < 0) { - BT_ERR("Can't register misc device with minor %d", minor); - return -EIO; - } - - return 0; + return misc_register(&vhci_miscdev); } static void __exit vhci_exit(void) { - if (misc_deregister(&vhci_miscdev) < 0) - BT_ERR("Can't unregister misc device with minor %d", minor); + misc_deregister(&vhci_miscdev); } module_init(vhci_init); -- cgit v1.2.3 From fed4c2508b7419d0a55958fead6151b32def1683 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 3 Dec 2009 18:07:28 +0100 Subject: Bluetooth: Fix miscdev ops owner for virtual driver The /dev/vhci ops don't refer to the module and so it is possible to unload the module while the file descriptor is in use. This was an accidental removal after the cleanup. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_vhci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index c1d389f2cbaf..7595274103fd 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -276,6 +276,7 @@ static int vhci_release(struct inode *inode, struct file *file) } static const struct file_operations vhci_fops = { + .owner = THIS_MODULE, .read = vhci_read, .write = vhci_write, .poll = vhci_poll, -- cgit v1.2.3 From 2da31939a42f7a676a0bc5155d6a0a39ed8451f2 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 26 Nov 2009 16:20:56 +0100 Subject: Bluetooth: Implement raw output support for HIDP layer Implement raw output callback which is used by hidraw to send raw data to the underlying device. Without this patch, the userspace hidraw-based applications can't send output reports to HID Bluetooth devices. Reported-and-tested-by: Brian Gunn Signed-off-by: Jiri Kosina Signed-off-by: Marcel Holtmann --- net/bluetooth/hidp/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 49d8495d69be..569750010fd3 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -280,6 +280,13 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep return hidp_queue_report(session, buf, rsize); } +static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count) +{ + if (hidp_queue_report(hid->driver_data, data, count)) + return -ENOMEM; + return count; +} + static void hidp_idle_timeout(unsigned long arg) { struct hidp_session *session = (struct hidp_session *) arg; @@ -785,6 +792,8 @@ static int hidp_setup_hid(struct hidp_session *session, hid->dev.parent = hidp_get_device(session); hid->ll_driver = &hidp_hid_driver; + hid->hid_output_raw_report = hidp_output_raw_report; + err = hid_add_device(hid); if (err < 0) goto failed; -- cgit v1.2.3 From 7e21addcd0ad87696c17409399e56e874931da57 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 18 Nov 2009 01:05:00 +0100 Subject: Bluetooth: Return ENETDOWN when interface is down Sending commands to a down interface results in a timeout while clearly it should just return ENETDOWN. When using the ioctls this works fine, but not when using the HCI sockets sendmsg interface. Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sock.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 1ca5c7ca9bd4..c3701f37aeb0 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -414,6 +414,11 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, goto done; } + if (!test_bit(HCI_UP, &hdev->flags)) { + err = -ENETDOWN; + goto done; + } + if (!(skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) goto done; -- cgit v1.2.3 From 76bca88012e1d27de794f32cc551d6314d38b6d9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 18 Nov 2009 00:40:39 +0100 Subject: Bluetooth: Turn hci_recv_frame into an exported function For future simplification it is important that the hci_recv_frame function is no longer an inline function. So move it into the module itself and export it. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 23 +---------------------- net/bluetooth/hci_core.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7b640aeddb64..8460f2283089 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -437,28 +437,7 @@ int hci_inquiry(void __user *arg); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); -/* Receive frame from HCI drivers */ -static inline int hci_recv_frame(struct sk_buff *skb) -{ - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - if (!hdev || (!test_bit(HCI_UP, &hdev->flags) - && !test_bit(HCI_INIT, &hdev->flags))) { - kfree_skb(skb); - return -ENXIO; - } - - /* Incomming skb */ - bt_cb(skb)->incoming = 1; - - /* Time stamp */ - __net_timestamp(skb); - - /* Queue frame for rx task */ - skb_queue_tail(&hdev->rx_q, skb); - hci_sched_rx(hdev); - return 0; -} - +int hci_recv_frame(struct sk_buff *skb); int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count); int hci_register_sysfs(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e1da8f68759c..3fc90e543ec1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -987,6 +987,29 @@ int hci_resume_dev(struct hci_dev *hdev) } EXPORT_SYMBOL(hci_resume_dev); +/* Receive frame from HCI drivers */ +int hci_recv_frame(struct sk_buff *skb) +{ + struct hci_dev *hdev = (struct hci_dev *) skb->dev; + if (!hdev || (!test_bit(HCI_UP, &hdev->flags) + && !test_bit(HCI_INIT, &hdev->flags))) { + kfree_skb(skb); + return -ENXIO; + } + + /* Incomming skb */ + bt_cb(skb)->incoming = 1; + + /* Time stamp */ + __net_timestamp(skb); + + /* Queue frame for rx task */ + skb_queue_tail(&hdev->rx_q, skb); + hci_sched_rx(hdev); + return 0; +} +EXPORT_SYMBOL(hci_recv_frame); + /* Receive packet type fragment */ #define __reassembly(hdev, type) ((hdev)->reassembly[(type) - 2]) -- cgit v1.2.3 From c78ae283145d3a8799b2fb01650166a66af3bff8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 18 Nov 2009 01:02:54 +0100 Subject: Bluetooth: Unobfuscate tasklet_schedule usage The tasklet schedule function helpers are just an obfuscation. So remove them and call the schedule functions directly. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 16 ---------------- net/bluetooth/hci_core.c | 18 ++++++++++++------ net/bluetooth/hci_event.c | 6 +++--- net/bluetooth/hci_sock.c | 6 +++--- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8460f2283089..7b86094a894b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -367,22 +367,6 @@ static inline void hci_conn_put(struct hci_conn *conn) } } -/* ----- HCI tasks ----- */ -static inline void hci_sched_cmd(struct hci_dev *hdev) -{ - tasklet_schedule(&hdev->cmd_task); -} - -static inline void hci_sched_rx(struct hci_dev *hdev) -{ - tasklet_schedule(&hdev->rx_task); -} - -static inline void hci_sched_tx(struct hci_dev *hdev) -{ - tasklet_schedule(&hdev->tx_task); -} - /* ----- HCI Devices ----- */ static inline void __hci_dev_put(struct hci_dev *d) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3fc90e543ec1..94ba34982021 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -193,8 +193,9 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) while ((skb = skb_dequeue(&hdev->driver_init))) { bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; skb->dev = (void *) hdev; + skb_queue_tail(&hdev->cmd_q, skb); - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); } skb_queue_purge(&hdev->driver_init); @@ -1005,7 +1006,8 @@ int hci_recv_frame(struct sk_buff *skb) /* Queue frame for rx task */ skb_queue_tail(&hdev->rx_q, skb); - hci_sched_rx(hdev); + tasklet_schedule(&hdev->rx_task); + return 0; } EXPORT_SYMBOL(hci_recv_frame); @@ -1216,8 +1218,9 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; skb->dev = (void *) hdev; + skb_queue_tail(&hdev->cmd_q, skb); - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); return 0; } @@ -1294,7 +1297,8 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) spin_unlock_bh(&conn->data_q.lock); } - hci_sched_tx(hdev); + tasklet_schedule(&hdev->tx_task); + return 0; } EXPORT_SYMBOL(hci_send_acl); @@ -1321,8 +1325,10 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) skb->dev = (void *) hdev; bt_cb(skb)->pkt_type = HCI_SCODATA_PKT; + skb_queue_tail(&conn->data_q, skb); - hci_sched_tx(hdev); + tasklet_schedule(&hdev->tx_task); + return 0; } EXPORT_SYMBOL(hci_send_sco); @@ -1635,7 +1641,7 @@ static void hci_cmd_task(unsigned long arg) hdev->cmd_last_tx = jiffies; } else { skb_queue_head(&hdev->cmd_q, skb); - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); } } } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e99fe385fba2..28517bad796c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1320,7 +1320,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk if (ev->ncmd) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); } } @@ -1386,7 +1386,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->ncmd) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); } } @@ -1454,7 +1454,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s } } - hci_sched_tx(hdev); + tasklet_schedule(&hdev->tx_task); tasklet_enable(&hdev->tx_task); } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index c3701f37aeb0..688cfebfbee0 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -445,10 +445,10 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) { skb_queue_tail(&hdev->raw_q, skb); - hci_sched_tx(hdev); + tasklet_schedule(&hdev->tx_task); } else { skb_queue_tail(&hdev->cmd_q, skb); - hci_sched_cmd(hdev); + tasklet_schedule(&hdev->cmd_task); } } else { if (!capable(CAP_NET_RAW)) { @@ -457,7 +457,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, } skb_queue_tail(&hdev->raw_q, skb); - hci_sched_tx(hdev); + tasklet_schedule(&hdev->tx_task); } err = len; -- cgit v1.2.3 From cde9f807f003676862178a6f28b52c7d431511ed Mon Sep 17 00:00:00 2001 From: Vikram Kandukuri Date: Thu, 3 Dec 2009 15:12:51 +0530 Subject: Bluetooth: Fix handling of BNEP setup connection requests According to BNEP test specification the proper response should be sent for a setup connection request message after the BNEP connection setup has been completed. Signed-off-by: Vikram Kandukuri Signed-off-by: Marcel Holtmann --- net/bluetooth/bnep/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index cafe9f54d841..29b1b220d6cf 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -230,7 +230,6 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) switch (cmd) { case BNEP_CMD_NOT_UNDERSTOOD: - case BNEP_SETUP_CONN_REQ: case BNEP_SETUP_CONN_RSP: case BNEP_FILTER_NET_TYPE_RSP: case BNEP_FILTER_MULTI_ADDR_RSP: @@ -245,6 +244,10 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) err = bnep_ctrl_set_mcfilter(s, data, len); break; + case BNEP_SETUP_CONN_REQ: + err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED); + break; + default: { u8 pkt[3]; pkt[0] = BNEP_CONTROL; -- cgit v1.2.3 From 0565c1c24af94130b891f989fa608faddfadc52c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 3 Oct 2009 02:34:36 -0300 Subject: Bluetooth: Initialize variables and timers for both channel's sides Fix ERTM's full-duplex channel to work as specified by ERTM spec. ERTM needs to handle state vars, timers and counters to send and receive I-frames(the data frames), i.e., for both sides of data communication. We initialize all of them to the default values here. Full-duplex channel is a mandatory feature of ERTM spec. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 54 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 54992f782301..dfd0327cf8da 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2173,6 +2173,21 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) *ptr += L2CAP_CONF_OPT_SIZE + len; } +static inline void l2cap_ertm_init(struct sock *sk) +{ + l2cap_pi(sk)->expected_ack_seq = 0; + l2cap_pi(sk)->unacked_frames = 0; + l2cap_pi(sk)->buffer_seq = 0; + l2cap_pi(sk)->num_to_ack = 0; + + setup_timer(&l2cap_pi(sk)->retrans_timer, + l2cap_retrans_timeout, (unsigned long) sk); + setup_timer(&l2cap_pi(sk)->monitor_timer, + l2cap_monitor_timeout, (unsigned long) sk); + + __skb_queue_head_init(SREJ_QUEUE(sk)); +} + static int l2cap_mode_supported(__u8 mode, __u32 feat_mask) { u32 local_feat_mask = l2cap_feat_mask; @@ -2761,17 +2776,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; sk->sk_state = BT_CONNECTED; - l2cap_pi(sk)->next_tx_seq = 0; - l2cap_pi(sk)->expected_ack_seq = 0; - l2cap_pi(sk)->unacked_frames = 0; - - setup_timer(&l2cap_pi(sk)->retrans_timer, - l2cap_retrans_timeout, (unsigned long) sk); - setup_timer(&l2cap_pi(sk)->monitor_timer, - l2cap_monitor_timeout, (unsigned long) sk); + l2cap_pi(sk)->next_tx_seq = 0; + l2cap_pi(sk)->expected_tx_seq = 0; __skb_queue_head_init(TX_QUEUE(sk)); - __skb_queue_head_init(SREJ_QUEUE(sk)); + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + l2cap_ertm_init(sk); + l2cap_chan_ready(sk); goto unlock; } @@ -2850,11 +2861,12 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16; sk->sk_state = BT_CONNECTED; + l2cap_pi(sk)->next_tx_seq = 0; l2cap_pi(sk)->expected_tx_seq = 0; - l2cap_pi(sk)->buffer_seq = 0; - l2cap_pi(sk)->num_to_ack = 0; __skb_queue_head_init(TX_QUEUE(sk)); - __skb_queue_head_init(SREJ_QUEUE(sk)); + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + l2cap_ertm_init(sk); + l2cap_chan_ready(sk); } @@ -2886,9 +2898,12 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; skb_queue_purge(TX_QUEUE(sk)); - skb_queue_purge(SREJ_QUEUE(sk)); - del_timer(&l2cap_pi(sk)->retrans_timer); - del_timer(&l2cap_pi(sk)->monitor_timer); + + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + skb_queue_purge(SREJ_QUEUE(sk)); + del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&l2cap_pi(sk)->monitor_timer); + } l2cap_chan_del(sk, ECONNRESET); bh_unlock_sock(sk); @@ -2913,9 +2928,12 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd return 0; skb_queue_purge(TX_QUEUE(sk)); - skb_queue_purge(SREJ_QUEUE(sk)); - del_timer(&l2cap_pi(sk)->retrans_timer); - del_timer(&l2cap_pi(sk)->monitor_timer); + + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + skb_queue_purge(SREJ_QUEUE(sk)); + del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&l2cap_pi(sk)->monitor_timer); + } l2cap_chan_del(sk, 0); bh_unlock_sock(sk); -- cgit v1.2.3 From 889a3ca466018ab68363c3168993793bc2d984f1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 3 Oct 2009 02:34:37 -0300 Subject: Bluetooth: Fix unset of SrejActioned flag SrejActioned is a flag that when set prevents local side to retransmit a I-frame(the data frame) already retransmitted. The local entity can retransmit again only when it receives a SREJ frame with the F-bit set. SREJ frame - Selective Reject frame - is sent when an entity wants the retransmission of a specific I-frame that was lost or corrupted. This bug can put ERTM in an unknown state once the entity can't retransmit. A frame with the Final bit set is expected when the local side sends a frame with the Poll bit set due to a local busy condition or a retransmission timer expired. (Receipt of P-bit shall always be replied by a frame with the F-bit set). pi->conn_state keeps informations about many ERTM flags including SrejActioned. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index dfd0327cf8da..2d5d37545b10 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3443,7 +3443,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str } else if (rx_control & L2CAP_CTRL_FINAL) { if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && pi->srej_save_reqseq == tx_seq) - pi->srej_save_reqseq &= ~L2CAP_CONN_SREJ_ACT; + pi->conn_state &= ~L2CAP_CONN_SREJ_ACT; else l2cap_retransmit_frame(sk, tx_seq); } -- cgit v1.2.3 From 9f121a5a80b4417c6db5a35e26d2e79c29c3fc0d Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 3 Oct 2009 02:34:38 -0300 Subject: Bluetooth: Fix sending ReqSeq on I-frames As specified by ERTM spec an ERTM channel can acknowledge received I-frames(the data frames) by sending an I-frame with the proper ReqSeq value (i.e. ReqSeq is set to BufferSeq). Until now we aren't setting the ReqSeq value on I-frame control bits. That way we can save sending S-frames(Supervise frames) only to acknowledge receipt of I-frames. It is very helpful to the full-duplex channel. ReqSeq is the packet sequence number sent in an acknowledgement frame to acknowledge receipt of frames up to (ReqSeq - 1). BufferSeq controls the receiver buffer, it is used to delay acknowledgement of new frames to not cause buffer overflow. BufferSeq value is not increased until frames are pulled by reassembly function. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap.c | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9516f4b4a3c2..327eb57dab51 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -324,7 +324,6 @@ struct l2cap_pinfo { __u8 next_tx_seq; __u8 expected_ack_seq; - __u8 req_seq; __u8 expected_tx_seq; __u8 buffer_seq; __u8 buffer_seq_srej; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 2d5d37545b10..78ab8811e5ef 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1333,7 +1333,7 @@ static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq) tx_skb = skb_clone(skb, GFP_ATOMIC); bt_cb(skb)->retries++; control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); - control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) + control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1375,7 +1375,7 @@ static int l2cap_ertm_send(struct sock *sk) bt_cb(skb)->retries++; control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); - control |= (pi->req_seq << L2CAP_CTRL_REQSEQ_SHIFT) + control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); @@ -3298,12 +3298,16 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str { struct l2cap_pinfo *pi = l2cap_pi(sk); u8 tx_seq = __get_txseq(rx_control); + u8 req_seq = __get_reqseq(rx_control); u16 tx_control = 0; u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; int err = 0; BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + pi->expected_ack_seq = req_seq; + l2cap_drop_acked_frames(sk); + if (tx_seq == pi->expected_tx_seq) goto expected; -- cgit v1.2.3 From 4ec10d9720ef78cd81d8bcc30a3238665744569f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 3 Oct 2009 02:34:39 -0300 Subject: Bluetooth: Implement RejActioned flag RejActioned is used to prevent retransmission when a entity is on the WAIT_F state, i.e., waiting for a frame with F-bit set due local busy condition or a expired retransmission timer. (When these two events raise they send a frame with the Poll bit set and enters in the WAIT_F state to wait for a frame with the Final bit set.) The local entity doesn't send I-frames(the data frames) until the receipt of a frame with F-bit set. When that happens it also set RejActioned to false. RejActioned is a mandatory feature of ERTM spec. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap.c | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 327eb57dab51..17a689f27a6a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -374,6 +374,7 @@ struct l2cap_pinfo { #define L2CAP_CONN_SEND_PBIT 0x10 #define L2CAP_CONN_REMOTE_BUSY 0x20 #define L2CAP_CONN_LOCAL_BUSY 0x40 +#define L2CAP_CONN_REJ_ACT 0x80 #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 78ab8811e5ef..73bda0ae41d6 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3362,6 +3362,16 @@ expected: return 0; } + if (rx_control & L2CAP_CTRL_FINAL) { + if (pi->conn_state & L2CAP_CONN_REJ_ACT) + pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + else { + sk->sk_send_head = TX_QUEUE(sk)->next; + pi->next_tx_seq = pi->expected_ack_seq; + l2cap_ertm_send(sk); + } + } + pi->buffer_seq = (pi->buffer_seq + 1) % 64; err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); @@ -3398,6 +3408,14 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); + if (pi->conn_state & L2CAP_CONN_REJ_ACT) + pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + else { + sk->sk_send_head = TX_QUEUE(sk)->next; + pi->next_tx_seq = pi->expected_ack_seq; + l2cap_ertm_send(sk); + } + if (!(pi->conn_state & L2CAP_CONN_WAIT_F)) break; @@ -3425,10 +3443,24 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str pi->expected_ack_seq = __get_reqseq(rx_control); l2cap_drop_acked_frames(sk); - sk->sk_send_head = TX_QUEUE(sk)->next; - pi->next_tx_seq = pi->expected_ack_seq; + if (rx_control & L2CAP_CTRL_FINAL) { + if (pi->conn_state & L2CAP_CONN_REJ_ACT) + pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + else { + sk->sk_send_head = TX_QUEUE(sk)->next; + pi->next_tx_seq = pi->expected_ack_seq; + l2cap_ertm_send(sk); + } + } else { + sk->sk_send_head = TX_QUEUE(sk)->next; + pi->next_tx_seq = pi->expected_ack_seq; + l2cap_ertm_send(sk); - l2cap_ertm_send(sk); + if (pi->conn_state & L2CAP_CONN_WAIT_F) { + pi->srej_save_reqseq = tx_seq; + pi->conn_state |= L2CAP_CONN_REJ_ACT; + } + } break; -- cgit v1.2.3 From 2ab25cdd7b54473dd42dcffc9872737de2517466 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 3 Oct 2009 02:34:40 -0300 Subject: Bluetooth: Fix 'SendRRorRNR' to send the ReqSeq value SendRRorRNR needs to acknowledge received I-frames (actually every packet needs to acknowledge received I-frames by sending the proper packet sequence number), so ReqSeq is set to the next I-frame number sequence to be pulled by the reassembly function. SendRRorRNR tells the remote side about local busy conditions, it sends a Receiver Ready frame if local busy is false or a Receiver Not Ready if local busy is true. ReqSeq is the packet's field to send the number of the acknowledged packets. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 73bda0ae41d6..c898f3439d1c 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -373,6 +373,8 @@ static inline int l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) else control |= L2CAP_SUPER_RCV_READY; + control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + return l2cap_send_sframe(pi, control); } -- cgit v1.2.3 From 32fd63981ed453bd882f22e3e9b0ccbc11fb47e5 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 30 Sep 2009 11:18:30 -0700 Subject: Bluetooth: Enable auto sleep mode for btmrvl driver The auto sleep mode for btmrvl driver is not enabled by default. This patch enables auto sleep mode when card is probed. Signed-off-by: Amitkumar Karwar Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_drv.h | 1 + drivers/bluetooth/btmrvl_main.c | 55 ++++++++++++++++++++++++----------------- drivers/bluetooth/btmrvl_sdio.c | 2 ++ 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 411c7a77082d..523d197b9824 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -131,6 +131,7 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); +int btmrvl_enable_ps(struct btmrvl_private *priv); int btmrvl_prepare_command(struct btmrvl_private *priv); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index e605563b4eaa..f97771ce432c 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -189,6 +189,38 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) } EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); +int btmrvl_enable_ps(struct btmrvl_private *priv) +{ + struct sk_buff *skb; + struct btmrvl_cmd *cmd; + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (skb == NULL) { + BT_ERR("No free skb"); + return -ENOMEM; + } + + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, + BT_CMD_AUTO_SLEEP_MODE)); + cmd->length = 1; + + if (priv->btmrvl_dev.psmode) + cmd->data[0] = BT_PS_ENABLE; + else + cmd->data[0] = BT_PS_DISABLE; + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb->dev = (void *) priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue PSMODE Command:%d", cmd->data[0]); + + return 0; +} +EXPORT_SYMBOL_GPL(btmrvl_enable_ps); + static int btmrvl_enable_hs(struct btmrvl_private *priv) { struct sk_buff *skb; @@ -258,28 +290,7 @@ int btmrvl_prepare_command(struct btmrvl_private *priv) if (priv->btmrvl_dev.pscmd) { priv->btmrvl_dev.pscmd = 0; - - skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); - if (skb == NULL) { - BT_ERR("No free skb"); - return -ENOMEM; - } - - cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); - cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_AUTO_SLEEP_MODE)); - cmd->length = 1; - - if (priv->btmrvl_dev.psmode) - cmd->data[0] = BT_PS_ENABLE; - else - cmd->data[0] = BT_PS_DISABLE; - - bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - - skb->dev = (void *) priv->btmrvl_dev.hcidev; - skb_queue_head(&priv->adapter->tx_queue, skb); - - BT_DBG("Queue PSMODE Command:%d", cmd->data[0]); + btmrvl_enable_ps(priv); } if (priv->btmrvl_dev.hscmd) { diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 5b33b85790f2..d6aaf511a4f4 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -930,6 +930,8 @@ static int btmrvl_sdio_probe(struct sdio_func *func, priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); + priv->btmrvl_dev.psmode = 1; + btmrvl_enable_ps(priv); return 0; -- cgit v1.2.3 From 5fbcd3d1a07e234583e17830e8aef47282c22141 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 5 Oct 2009 11:35:43 +0200 Subject: Bluetooth: Add L2CAP option for max transmit value For testing purposes it is important to modify the max transmit value. Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c898f3439d1c..5129b88c8e5b 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -54,6 +54,7 @@ #define VERSION "2.14" static int enable_ertm = 0; +static int max_transmit = L2CAP_DEFAULT_MAX_TX; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u8 l2cap_fixed_chan[8] = { 0x02, }; @@ -2253,7 +2254,7 @@ done: case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; - rfc.max_transmit = L2CAP_DEFAULT_MAX_TX; + rfc.max_transmit = max_transmit; rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); @@ -4060,6 +4061,9 @@ module_exit(l2cap_exit); module_param(enable_ertm, bool, 0644); MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode"); +module_param(max_transmit, uint, 0644); +MODULE_PARM_DESC(max_transmit, "Max transmit value (default = 3)"); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); MODULE_VERSION(VERSION); -- cgit v1.2.3 From eae38eede2e5f70d65f09327297bd698b0d3ea7e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 5 Oct 2009 12:23:48 +0200 Subject: Bluetooth: Add RFCOMM option to use L2CAP ERTM mode By default the RFCOMM layer would still use L2CAP basic mode. For testing purposes this option enables RFCOMM to select enhanced retransmission mode. Signed-off-by: Marcel Holtmann --- net/bluetooth/rfcomm/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 25692bc0a342..fc5ee3296e22 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -51,6 +51,7 @@ static int disable_cfc = 0; static int channel_mtu = -1; static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU; +static int l2cap_ertm = 0; static struct task_struct *rfcomm_thread; @@ -702,6 +703,8 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst sk = sock->sk; lock_sock(sk); l2cap_pi(sk)->imtu = l2cap_mtu; + if (l2cap_ertm) + l2cap_pi(sk)->mode = L2CAP_MODE_ERTM; release_sock(sk); s = rfcomm_session_add(sock, BT_BOUND); @@ -2185,6 +2188,9 @@ 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"); +module_param(l2cap_ertm, bool, 0644); +MODULE_PARM_DESC(l2cap_ertm, "Use L2CAP ERTM mode for connection"); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION); MODULE_VERSION(VERSION); -- cgit v1.2.3 From 2861453b1b5e022fd5e1294b8fbf39254440b661 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 21:41:18 +0000 Subject: Bluetooth: Declare MODULE_FIRMWARE for Marvell SDIO driver Signed-off-by: Ben Hutchings Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_sdio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index d6aaf511a4f4..1e6eb1aeba2b 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1003,3 +1003,5 @@ MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL v2"); +MODULE_FIRMWARE("sd8688_helper.bin"); +MODULE_FIRMWARE("sd8688.bin"); -- cgit v1.2.3