]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - net/bluetooth/l2cap.c
Bluetooth: Convert debug files to actually use debugfs instead of sysfs
[linux-2.6.git] / net / bluetooth / l2cap.c
index dfd0327cf8da5564a862b9d73dab12791c14203a..43e17f7d7ecd431f81704fc5bc94ec4c0bde9b2b 100644 (file)
@@ -40,6 +40,8 @@
 #include <linux/skbuff.h>
 #include <linux/list.h>
 #include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/crc16.h>
 #include <net/sock.h>
@@ -54,6 +56,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, };
@@ -373,6 +376,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);
 }
 
@@ -1209,6 +1214,7 @@ static void l2cap_monitor_timeout(unsigned long arg)
        bh_lock_sock(sk);
        if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) {
                l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk);
+               bh_unlock_sock(sk);
                return;
        }
 
@@ -1333,7 +1339,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);
 
@@ -1364,7 +1370,6 @@ static int l2cap_ertm_send(struct sock *sk)
 
        while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) &&
               !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) {
-               tx_skb = skb_clone(skb, GFP_ATOMIC);
 
                if (pi->remote_max_tx &&
                                bt_cb(skb)->retries == pi->remote_max_tx) {
@@ -1372,10 +1377,12 @@ static int l2cap_ertm_send(struct sock *sk)
                        break;
                }
 
+               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)
                                | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
                put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
 
@@ -2251,7 +2258,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);
@@ -3298,12 +3305,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;
 
@@ -3358,6 +3369,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);
@@ -3394,6 +3415,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;
 
@@ -3410,8 +3439,8 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
                            (pi->unacked_frames > 0))
                                __mod_retrans_timer();
 
-                       l2cap_ertm_send(sk);
                        pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+                       l2cap_ertm_send(sk);
                }
                break;
 
@@ -3421,10 +3450,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;
 
@@ -3432,9 +3475,9 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
                pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 
                if (rx_control & L2CAP_CTRL_POLL) {
-                       l2cap_retransmit_frame(sk, tx_seq);
                        pi->expected_ack_seq = tx_seq;
                        l2cap_drop_acked_frames(sk);
+                       l2cap_retransmit_frame(sk, tx_seq);
                        l2cap_ertm_send(sk);
                        if (pi->conn_state & L2CAP_CONN_WAIT_F) {
                                pi->srej_save_reqseq = tx_seq;
@@ -3443,7 +3486,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);
                }
@@ -3478,7 +3521,6 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
        struct l2cap_pinfo *pi;
        u16 control, len;
        u8 tx_seq;
-       int err;
 
        sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
        if (!sk) {
@@ -3530,13 +3572,11 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                        goto drop;
 
                if (__is_iframe(control))
-                       err = l2cap_data_channel_iframe(sk, control, skb);
+                       l2cap_data_channel_iframe(sk, control, skb);
                else
-                       err = l2cap_data_channel_sframe(sk, control, skb);
+                       l2cap_data_channel_sframe(sk, control, skb);
 
-               if (!err)
-                       goto done;
-               break;
+               goto done;
 
        case L2CAP_MODE_STREAMING:
                control = get_unaligned_le16(skb->data);
@@ -3562,7 +3602,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                else
                        pi->expected_tx_seq = tx_seq + 1;
 
-               err = l2cap_sar_reassembly_sdu(sk, skb, control);
+               l2cap_sar_reassembly_sdu(sk, skb, control);
 
                goto done;
 
@@ -3899,29 +3939,42 @@ drop:
        return 0;
 }
 
-static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
+static int l2cap_debugfs_show(struct seq_file *f, void *p)
 {
        struct sock *sk;
        struct hlist_node *node;
-       char *str = buf;
 
        read_lock_bh(&l2cap_sk_list.lock);
 
        sk_for_each(sk, node, &l2cap_sk_list.head) {
                struct l2cap_pinfo *pi = l2cap_pi(sk);
 
-               str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n",
-                               batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
-                               sk->sk_state, __le16_to_cpu(pi->psm), pi->scid,
-                               pi->dcid, pi->imtu, pi->omtu, pi->sec_level);
+               seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n",
+                                       batostr(&bt_sk(sk)->src),
+                                       batostr(&bt_sk(sk)->dst),
+                                       sk->sk_state, __le16_to_cpu(pi->psm),
+                                       pi->scid, pi->dcid,
+                                       pi->imtu, pi->omtu, pi->sec_level);
        }
 
        read_unlock_bh(&l2cap_sk_list.lock);
 
-       return str - buf;
+       return 0;
 }
 
-static CLASS_ATTR(l2cap, S_IRUGO, l2cap_sysfs_show, NULL);
+static int l2cap_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, l2cap_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations l2cap_debugfs_fops = {
+       .open           = l2cap_debugfs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static struct dentry *l2cap_debugfs;
 
 static const struct proto_ops l2cap_sock_ops = {
        .family         = PF_BLUETOOTH,
@@ -3981,8 +4034,12 @@ static int __init l2cap_init(void)
                goto error;
        }
 
-       if (class_create_file(bt_class, &class_attr_l2cap) < 0)
-               BT_ERR("Failed to create L2CAP info file");
+       if (bt_debugfs) {
+               l2cap_debugfs = debugfs_create_file("l2cap", 0444,
+                                       bt_debugfs, NULL, &l2cap_debugfs_fops);
+               if (!l2cap_debugfs)
+                       BT_ERR("Failed to create L2CAP debug file");
+       }
 
        BT_INFO("L2CAP ver %s", VERSION);
        BT_INFO("L2CAP socket layer initialized");
@@ -3996,7 +4053,7 @@ error:
 
 static void __exit l2cap_exit(void)
 {
-       class_remove_file(bt_class, &class_attr_l2cap);
+       debugfs_remove(l2cap_debugfs);
 
        if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
                BT_ERR("L2CAP socket unregistration failed");
@@ -4022,6 +4079,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 <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
 MODULE_VERSION(VERSION);