From fd059b9bd0af2e217f29d5a34e1c71039d26af8c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 10 May 2010 14:22:56 -0300 Subject: Bluetooth: Remove max_tx and tx_window module paramenters from L2CAP We don't need these parameters anymore since we have socket options for them. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index cf3c4073a8a6..fd507cbc7932 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -60,8 +60,6 @@ static int enable_ertm = 1; #else static int enable_ertm = 0; #endif -static int max_transmit = L2CAP_DEFAULT_MAX_TX; -static int tx_window = L2CAP_DEFAULT_TX_WINDOW; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u8 l2cap_fixed_chan[8] = { 0x02, }; @@ -816,9 +814,9 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->mode = L2CAP_MODE_ERTM; else pi->mode = L2CAP_MODE_BASIC; - pi->max_tx = max_transmit; + pi->max_tx = L2CAP_DEFAULT_MAX_TX; pi->fcs = L2CAP_FCS_CRC16; - pi->tx_win = tx_window; + pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; pi->sec_level = BT_SECURITY_LOW; pi->role_switch = 0; pi->force_reliable = 0; @@ -4682,12 +4680,6 @@ 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_param(tx_window, uint, 0644); -MODULE_PARM_DESC(tx_window, "Transmission window size value (default = 63)"); - MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); MODULE_VERSION(VERSION); -- cgit v1.2.3 From 0b31c85ce78d3646ac1e90d62969e7cd8cfd8b15 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 10 May 2010 14:26:11 -0300 Subject: Bluetooth: Remove L2CAP Extended Features from Kconfig This reverts commit 84fb0a6334af0ccad3544f6972c055d90fbb9fbe which adds the L2CAP Extended Features to the Kconfig, that is actually not needed. One can use other mechanisms to enable L2CAP Extended Features. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/Kconfig | 13 ------------- net/bluetooth/l2cap.c | 4 ---- 2 files changed, 17 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index ee3b3049d385..ed371684c133 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -43,19 +43,6 @@ config BT_L2CAP Say Y here to compile L2CAP support into the kernel or say M to compile it as module (l2cap). -config BT_L2CAP_EXT_FEATURES - bool "L2CAP Extended Features support (EXPERIMENTAL)" - depends on BT_L2CAP && EXPERIMENTAL - help - This option enables the L2CAP Extended Features support. These - new features include the Enhanced Retransmission and Streaming - Modes, the Frame Check Sequence (FCS), and Segmentation and - Reassembly (SAR) for L2CAP packets. They are a required for the - new Alternate MAC/PHY and the Bluetooth Medical Profile. - - You should say N unless you know what you are doing. Note that - this is in an experimental state yet. - config BT_SCO tristate "SCO links support" depends on BT diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index fd507cbc7932..6c5462b2a244 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -55,11 +55,7 @@ #define VERSION "2.14" -#ifdef CONFIG_BT_L2CAP_EXT_FEATURES -static int enable_ertm = 1; -#else static int enable_ertm = 0; -#endif static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u8 l2cap_fixed_chan[8] = { 0x02, }; -- cgit v1.2.3 From f6337c771126420c348b702e012262cfb5f0d56e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 10 May 2010 18:32:04 -0300 Subject: Bluetooth: Fix drop of packets with invalid req_seq/tx_seq We shall not use an unsigned var since we are expecting negatives value there. Using unsigned causes ERTM connection to close due to invalid ReqSeq numbers. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 6c5462b2a244..7e39d9ee0b9c 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3796,7 +3796,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str u8 tx_seq = __get_txseq(rx_control); u8 req_seq = __get_reqseq(rx_control); u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; - u8 tx_seq_offset, expected_tx_seq_offset; + int tx_seq_offset, expected_tx_seq_offset; int num_to_ack = (pi->tx_win/6) + 1; int err = 0; @@ -4081,7 +4081,8 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk struct sock *sk; struct l2cap_pinfo *pi; u16 control, len; - u8 tx_seq, req_seq, next_tx_seq_offset, req_seq_offset; + u8 tx_seq, req_seq; + int next_tx_seq_offset, req_seq_offset; sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); if (!sk) { -- cgit v1.2.3 From 8ff50ec04a7ecdbba6e0a5423cf6f2c5f7fc605e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 10 May 2010 19:34:11 -0300 Subject: Bluetooth: Fix bug with ERTM vars increment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All ERTM operations regarding the txWindow should be modulo 64, otherwise we confuse the ERTM logic and connections will break. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 7e39d9ee0b9c..a9fdfe401f5b 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3748,7 +3748,7 @@ static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) l2cap_ertm_reassembly_sdu(sk, skb, control); l2cap_pi(sk)->buffer_seq_srej = (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; - tx_seq++; + tx_seq = (tx_seq + 1) % 64; } } @@ -3784,10 +3784,11 @@ static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) l2cap_send_sframe(pi, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); - new->tx_seq = pi->expected_tx_seq++; + new->tx_seq = pi->expected_tx_seq; + pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; list_add_tail(&new->list, SREJ_LIST(sk)); } - pi->expected_tx_seq++; + pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; } static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) -- cgit v1.2.3 From bc1b1f8bee63966649dd5ac7d10d31a6556bf19b Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 11 May 2010 22:14:00 -0300 Subject: Bluetooth: Only check SAR bits if frame is an I-frame The SAR bits doesn't make sense for an S-frame. It doesn't use SAR. Checking SAR for a S-frames can lead to L2CAP errors, it could close the channel with an invalid packet length, since we was removing the 2 of the of any frame that match SAR start bits, without check if it is an I-frame. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index a9fdfe401f5b..108c2f290ac5 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -4117,7 +4117,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk skb_pull(skb, 2); len = skb->len; - if (__is_sar_start(control)) + if (__is_sar_start(control) && __is_iframe(control)) len -= 2; if (pi->fcs == L2CAP_FCS_CRC16) -- cgit v1.2.3 From 6e2b6722abaa3f6042357e11f465488b7c12f94c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 1 Jun 2010 18:52:58 -0300 Subject: Bluetooth: Fix bug in l2cap_ertm_send() behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch makes l2cap_ertm_send() similar to the Send-Data action of the ERTM spec. We shall not check for RemoteBusy or WAIT_F state inside l2cap_ertm_send(). Such checks were causing a bug in the retransmission logic of ERTM and making ERTM stalls until the ACL is dropped. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 108c2f290ac5..69f098d98141 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1415,11 +1415,8 @@ static int l2cap_ertm_send(struct sock *sk) u16 control, fcs; int nsent = 0; - if (pi->conn_state & L2CAP_CONN_WAIT_F) - return 0; - while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) && - !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) { + while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) { if (pi->remote_max_tx && bt_cb(skb)->retries == pi->remote_max_tx) { @@ -1792,6 +1789,11 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (pi->mode == L2CAP_MODE_STREAMING) { err = l2cap_streaming_send(sk); } else { + if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && + pi->conn_state && L2CAP_CONN_WAIT_F) { + err = len; + break; + } spin_lock_bh(&pi->send_lock); err = l2cap_ertm_send(sk); spin_unlock_bh(&pi->send_lock); @@ -3378,8 +3380,6 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0) __mod_retrans_timer(); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - spin_lock_bh(&pi->send_lock); l2cap_ertm_send(sk); spin_unlock_bh(&pi->send_lock); -- cgit v1.2.3 From bfbacc11550a785caf082f3ccfcd7ecf882e09a4 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Mon, 31 May 2010 18:35:44 -0300 Subject: Bluetooth: Fix SREJ_QUEUE corruption in L2CAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since all TxSeq values are modulo, we shall not compare them directly. We have to compare their offset inside the TxWindow instead. Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 69f098d98141..b89762134e4e 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3394,6 +3394,8 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) { struct sk_buff *next_skb; + struct l2cap_pinfo *pi = l2cap_pi(sk); + int tx_seq_offset, next_tx_seq_offset; bt_cb(skb)->tx_seq = tx_seq; bt_cb(skb)->sar = sar; @@ -3404,11 +3406,20 @@ static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_s return 0; } + tx_seq_offset = (tx_seq - pi->buffer_seq) % 64; + if (tx_seq_offset < 0) + tx_seq_offset += 64; + do { if (bt_cb(next_skb)->tx_seq == tx_seq) return -EINVAL; - if (bt_cb(next_skb)->tx_seq > tx_seq) { + next_tx_seq_offset = (bt_cb(next_skb)->tx_seq - + pi->buffer_seq) % 64; + if (next_tx_seq_offset < 0) + next_tx_seq_offset += 64; + + if (next_tx_seq_offset > tx_seq_offset) { __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb); return 0; } -- cgit v1.2.3 From 51893f88dd916efead5e24a212c907b2cd35e160 Mon Sep 17 00:00:00 2001 From: Nathan Holstein Date: Wed, 9 Jun 2010 15:46:25 -0400 Subject: Bluetooth: Fix bug with ERTM minimum packet length ERTM and streaming mode L2CAP sockets have no minimum packet length. Only basic mode connections have minimum length. Instead, validate the packet containing all necessary control, FCS, and SAR fields. The patch fixes the drop of valid packets with length lower than 4. Signed-off-by: Nathan Holstein Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index b89762134e4e..4af8fc0d512c 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -4092,9 +4092,9 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk { struct sock *sk; struct l2cap_pinfo *pi; - u16 control, len; + u16 control; u8 tx_seq, req_seq; - int next_tx_seq_offset, req_seq_offset; + int len, next_tx_seq_offset, req_seq_offset; sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); if (!sk) { @@ -4164,7 +4164,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk } if (__is_iframe(control)) { - if (len < 4) { + if (len < 0) { l2cap_send_disconn_req(pi->conn, sk); goto drop; } @@ -4192,7 +4192,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (pi->fcs == L2CAP_FCS_CRC16) len -= 2; - if (len > pi->mps || len < 4 || __is_sframe(control)) + if (len > pi->mps || len < 0 || __is_sframe(control)) goto drop; if (l2cap_check_fcs(pi, skb)) -- cgit v1.2.3 From c13ffa620f15cb28d18268a773464cf51550fa9f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 13 May 2010 20:50:12 -0300 Subject: Bluetooth: Proper shutdown ERTM when closing the channel Fix a crash regarding the Monitor Timeout, it was running even after the shutdown of the ACL connection, which doesn't make sense. The same code also fixes another issue, before this patch L2CAP was sending many Disconnections Requests while we have to send only one. The issues are related to each other, a expired Monitor Timeout can trigger a Disconnection Request and then we may have a crash if the link was already deleted. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 59 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 22 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 4af8fc0d512c..4415eb48c6ae 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -272,6 +272,24 @@ static void l2cap_chan_del(struct sock *sk, int err) parent->sk_data_ready(parent, 0); } else sk->sk_state_change(sk); + + skb_queue_purge(TX_QUEUE(sk)); + + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + struct srej_list *l, *tmp; + + del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&l2cap_pi(sk)->monitor_timer); + del_timer(&l2cap_pi(sk)->ack_timer); + + skb_queue_purge(SREJ_QUEUE(sk)); + skb_queue_purge(BUSY_QUEUE(sk)); + + list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { + list_del(&l->list); + kfree(l); + } + } } /* Service level security */ @@ -345,8 +363,12 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) struct sk_buff *skb; struct l2cap_hdr *lh; struct l2cap_conn *conn = pi->conn; + struct sock *sk = (struct sock *)pi; int count, hlen = L2CAP_HDR_SIZE + 2; + if (sk->sk_state != BT_CONNECTED) + return; + if (pi->fcs == L2CAP_FCS_CRC16) hlen += 2; @@ -438,10 +460,23 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk) { struct l2cap_disconn_req req; + if (!conn) + return; + + skb_queue_purge(TX_QUEUE(sk)); + + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&l2cap_pi(sk)->monitor_timer); + del_timer(&l2cap_pi(sk)->ack_timer); + } + req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); req.scid = cpu_to_le16(l2cap_pi(sk)->scid); l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, sizeof(req), &req); + + sk->sk_state = BT_DISCONN; } /* ---- L2CAP connections ---- */ @@ -734,7 +769,6 @@ static void __l2cap_sock_close(struct sock *sk, int reason) sk->sk_type == SOCK_STREAM) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; - sk->sk_state = BT_DISCONN; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); l2cap_send_disconn_req(conn, sk); } else @@ -1415,6 +1449,8 @@ static int l2cap_ertm_send(struct sock *sk) u16 control, fcs; int nsent = 0; + if (sk->sk_state != BT_CONNECTED) + return -ENOTCONN; while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) { @@ -3072,7 +3108,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr } default: - sk->sk_state = BT_DISCONN; sk->sk_err = ECONNRESET; l2cap_sock_set_timer(sk, HZ * 5); l2cap_send_disconn_req(conn, sk); @@ -3126,16 +3161,6 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; - skb_queue_purge(TX_QUEUE(sk)); - - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { - skb_queue_purge(SREJ_QUEUE(sk)); - skb_queue_purge(BUSY_QUEUE(sk)); - del_timer(&l2cap_pi(sk)->retrans_timer); - del_timer(&l2cap_pi(sk)->monitor_timer); - del_timer(&l2cap_pi(sk)->ack_timer); - } - l2cap_chan_del(sk, ECONNRESET); bh_unlock_sock(sk); @@ -3158,16 +3183,6 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd if (!sk) return 0; - skb_queue_purge(TX_QUEUE(sk)); - - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { - skb_queue_purge(SREJ_QUEUE(sk)); - skb_queue_purge(BUSY_QUEUE(sk)); - del_timer(&l2cap_pi(sk)->retrans_timer); - del_timer(&l2cap_pi(sk)->monitor_timer); - del_timer(&l2cap_pi(sk)->ack_timer); - } - l2cap_chan_del(sk, 0); bh_unlock_sock(sk); -- cgit v1.2.3 From 95ffa97827371ede501615d9bd048eb5b49e8fe1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 18 Jun 2010 20:37:33 -0300 Subject: Bluetooth: Fix L2CAP control bit field corruption When resending an I-frame, ERTM was reusing the control bits from the last time it was sent, that was causing a corruption in the new control field due to it dirty fields. This patches extracts only the SAR bits from the old field and reuse it to resend the packet, the others bits should be reset and receive the updated value. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 4415eb48c6ae..c2fb26d9286c 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1430,6 +1430,8 @@ static void l2cap_retransmit_one_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 &= L2CAP_CTRL_SAR; + control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1465,6 +1467,8 @@ static int l2cap_ertm_send(struct sock *sk) bt_cb(skb)->retries++; control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + control &= L2CAP_CTRL_SAR; + if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { control |= L2CAP_CTRL_FINAL; pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; -- cgit v1.2.3 From 7fe9b298c98fdfecf3b0efb4c971b7696d091ae9 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 12 May 2010 18:32:04 -0300 Subject: Bluetooth: Stop ack_timer if ERTM enters in Local Busy or SREJ_SENT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ack_timer is implemation specific, disabling it in such situation avoids some potencial errors in the ERTM protocol. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c2fb26d9286c..40cf67c11d20 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3665,6 +3665,8 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) pi->conn_state |= L2CAP_CONN_RNR_SENT; + del_timer(&pi->ack_timer); + queue_work(_busy_wq, &pi->busy_work); return err; @@ -3914,6 +3916,8 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str pi->conn_state |= L2CAP_CONN_SEND_PBIT; l2cap_send_srejframe(sk, tx_seq); + + del_timer(&pi->ack_timer); } return 0; -- cgit v1.2.3 From 2ece3684b4037ad2394de795d67abbe412ab5e2f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 16 Jun 2010 17:21:44 -0300 Subject: Bluetooth: Update buffer_seq before retransmit frames Updating buffer_seq first make us able to ack the last I-frame received. This is also a requirement of the Profile Tuning Suite software. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 40cf67c11d20..ecf3e3dcefe3 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3931,6 +3931,10 @@ expected: return 0; } + err = l2cap_push_rx_skb(sk, skb, rx_control); + if (err < 0) + return 0; + if (rx_control & L2CAP_CTRL_FINAL) { if (pi->conn_state & L2CAP_CONN_REJ_ACT) pi->conn_state &= ~L2CAP_CONN_REJ_ACT; @@ -3938,10 +3942,6 @@ expected: l2cap_retransmit_frames(sk); } - err = l2cap_push_rx_skb(sk, skb, rx_control); - if (err < 0) - return 0; - __mod_ack_timer(); pi->num_acked = (pi->num_acked + 1) % num_to_ack; -- cgit v1.2.3 From 3cb123d1c03a0510d3c325bfaa971ce4df1e050d Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 29 May 2010 02:24:35 -0300 Subject: Bluetooth: Fix handle of received P-bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ERTM spec mandates that after receive a P-bit we shall send an F-bit in response. This patch fixes this for retransmitted packets, on retransmitting we were missing to check for a pending F-bit to be sent. Also we were missing some annotation to send a F-bit. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index ecf3e3dcefe3..f0441b0b0335 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1430,10 +1430,15 @@ static void l2cap_retransmit_one_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 &= L2CAP_CTRL_SAR; + + if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + control |= L2CAP_CTRL_FINAL; + pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + } control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); + put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); if (pi->fcs == L2CAP_FCS_CRC16) { @@ -3385,7 +3390,6 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) u16 control = 0; pi->frames_sent = 0; - pi->conn_state |= L2CAP_CONN_SEND_FBIT; control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; @@ -3963,6 +3967,7 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) l2cap_drop_acked_frames(sk); if (rx_control & L2CAP_CTRL_POLL) { + pi->conn_state |= L2CAP_CONN_SEND_FBIT; if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && (pi->unacked_frames > 0)) @@ -4030,6 +4035,8 @@ static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control) if (rx_control & L2CAP_CTRL_POLL) { pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); + + pi->conn_state |= L2CAP_CONN_SEND_FBIT; l2cap_retransmit_one_frame(sk, tx_seq); spin_lock_bh(&pi->send_lock); @@ -4064,6 +4071,9 @@ static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control) pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); + if (rx_control & L2CAP_CTRL_POLL) + pi->conn_state |= L2CAP_CONN_SEND_FBIT; + if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) { del_timer(&pi->retrans_timer); if (rx_control & L2CAP_CTRL_POLL) -- cgit v1.2.3 From 45d65c46acc39945219eeb3752367ee80ed82799 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 7 Jun 2010 19:21:30 -0300 Subject: Bluetooth: Check the tx_window size on setsockopt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have to check if the proposed tx_window value is not greater that maximum value supported. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index f0441b0b0335..6094870d5d2a 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1912,6 +1912,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } + if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) { + err = -EINVAL; + break; + } + l2cap_pi(sk)->mode = opts.mode; switch (l2cap_pi(sk)->mode) { case L2CAP_MODE_BASIC: -- cgit v1.2.3 From 260000896750690b774d4343294ae5cbff1423e5 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 11 May 2010 22:02:00 -0300 Subject: Bluetooth: Check packet FCS earlier This way, if FCS is enabled and the packet is corrupted, we just drop it without read it len, which could be corrupted. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 6094870d5d2a..8c9f577dd46d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -4166,25 +4166,25 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk skb_pull(skb, 2); len = skb->len; + /* + * We can just drop the corrupted I-frame here. + * Receiver will miss it and start proper recovery + * procedures and ask retransmission. + */ + if (l2cap_check_fcs(pi, skb)) + goto drop; + if (__is_sar_start(control) && __is_iframe(control)) len -= 2; if (pi->fcs == L2CAP_FCS_CRC16) len -= 2; - /* - * We can just drop the corrupted I-frame here. - * Receiver will miss it and start proper recovery - * procedures and ask retransmission. - */ if (len > pi->mps) { l2cap_send_disconn_req(pi->conn, sk); goto drop; } - if (l2cap_check_fcs(pi, skb)) - goto drop; - req_seq = __get_reqseq(control); req_seq_offset = (req_seq - pi->expected_ack_seq) % 64; if (req_seq_offset < 0) @@ -4224,6 +4224,9 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk skb_pull(skb, 2); len = skb->len; + if (l2cap_check_fcs(pi, skb)) + goto drop; + if (__is_sar_start(control)) len -= 2; @@ -4233,9 +4236,6 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (len > pi->mps || len < 0 || __is_sframe(control)) goto drop; - if (l2cap_check_fcs(pi, skb)) - goto drop; - tx_seq = __get_txseq(control); if (pi->expected_tx_seq == tx_seq) -- cgit v1.2.3 From 4ea727ef9d507413f15da0de401d8a50b125649a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 3 Jun 2010 16:34:20 -0300 Subject: Bluetooth: Fix missing retransmission action with RR(P=1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Bluetooth SIG Profile Tuning Suite Software uses the CSA1 spec to run the L2CAP tests. The new 3.0 spec has a missing Retransmit-I-Frames action when the Remote side is Busy. We still start the retransmission timer if Remote is Busy and unacked frames > 0. We do everything we did before this change plus the Retransmission of I-frames. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 8c9f577dd46d..7c2273732909 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3405,8 +3405,8 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; } - if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0) - __mod_retrans_timer(); + if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY) + l2cap_retransmit_frames(sk); spin_lock_bh(&pi->send_lock); l2cap_ertm_send(sk); -- cgit v1.2.3 From 9b108fc0cf4e79c34a7d5626f5c2c4c529ef6d3f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 20 May 2010 16:21:53 -0300 Subject: Bluetooth: Fix ERTM error reporting to the userspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If any error occurs during transfers we have to tell userspace that something wrong happened. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 7c2273732909..1e39d72b80af 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -456,7 +456,7 @@ static void l2cap_do_start(struct sock *sk) } } -static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk) +static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) { struct l2cap_disconn_req req; @@ -477,6 +477,7 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk) L2CAP_DISCONN_REQ, sizeof(req), &req); sk->sk_state = BT_DISCONN; + sk->sk_err = err; } /* ---- L2CAP connections ---- */ @@ -770,7 +771,7 @@ static void __l2cap_sock_close(struct sock *sk, int reason) struct l2cap_conn *conn = l2cap_pi(sk)->conn; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); - l2cap_send_disconn_req(conn, sk); + l2cap_send_disconn_req(conn, sk, reason); } else l2cap_chan_del(sk, reason); break; @@ -1315,7 +1316,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); + l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED); bh_unlock_sock(sk); return; } @@ -1423,7 +1424,7 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) if (pi->remote_max_tx && bt_cb(skb)->retries == pi->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, sk); + l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); return; } @@ -1463,7 +1464,7 @@ static int l2cap_ertm_send(struct sock *sk) if (pi->remote_max_tx && bt_cb(skb)->retries == pi->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, sk); + l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); break; } @@ -2191,6 +2192,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } + + if (!err && sk->sk_err) + err = -sk->sk_err; + release_sock(sk); return err; } @@ -2462,7 +2467,7 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) case L2CAP_MODE_ERTM: pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) - l2cap_send_disconn_req(pi->conn, sk); + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); break; default: pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); @@ -3030,7 +3035,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Complete config. */ len = l2cap_parse_conf_req(sk, rsp); if (len < 0) { - l2cap_send_disconn_req(conn, sk); + l2cap_send_disconn_req(conn, sk, ECONNRESET); goto unlock; } @@ -3100,7 +3105,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr char req[64]; if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { - l2cap_send_disconn_req(conn, sk); + l2cap_send_disconn_req(conn, sk, ECONNRESET); goto done; } @@ -3109,7 +3114,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr len = l2cap_parse_conf_rsp(sk, rsp->data, len, req, &result); if (len < 0) { - l2cap_send_disconn_req(conn, sk); + l2cap_send_disconn_req(conn, sk, ECONNRESET); goto done; } @@ -3124,7 +3129,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr default: sk->sk_err = ECONNRESET; l2cap_sock_set_timer(sk, HZ * 5); - l2cap_send_disconn_req(conn, sk); + l2cap_send_disconn_req(conn, sk, ECONNRESET); goto done; } @@ -3565,7 +3570,7 @@ drop: pi->sdu = NULL; disconnect: - l2cap_send_disconn_req(pi->conn, sk); + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); kfree_skb(skb); return 0; } @@ -3588,7 +3593,7 @@ static void l2cap_busy_work(struct work_struct *work) if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { err = -EBUSY; - l2cap_send_disconn_req(pi->conn, sk); + l2cap_send_disconn_req(pi->conn, sk, EBUSY); goto done; } @@ -3864,7 +3869,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str /* invalid tx_seq */ if (tx_seq_offset >= pi->tx_win) { - l2cap_send_disconn_req(pi->conn, sk); + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); goto drop; } @@ -4181,7 +4186,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk len -= 2; if (len > pi->mps) { - l2cap_send_disconn_req(pi->conn, sk); + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); goto drop; } @@ -4197,20 +4202,20 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk /* check for invalid req-seq */ if (req_seq_offset > next_tx_seq_offset) { - l2cap_send_disconn_req(pi->conn, sk); + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); goto drop; } if (__is_iframe(control)) { if (len < 0) { - l2cap_send_disconn_req(pi->conn, sk); + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); goto drop; } l2cap_data_channel_iframe(sk, control, skb); } else { if (len != 0) { - l2cap_send_disconn_req(pi->conn, sk); + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); goto drop; } -- cgit v1.2.3 From 0e98958d4f827f814444757e0376546b462dfe6f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 19 Apr 2010 14:45:38 -0300 Subject: Bluetooth: Add debug output to ERTM code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the dynamic debug to output info about ERTM protocol stuff. The following script can be used to enable debug for ERTM: DEBUGFS="/sys/kernel/debug/dynamic_debug/control" echo -n 'func l2cap_send_disconn_req +p' > $DEBUGFS echo -n 'func l2cap_monitor_timeout +p' > $DEBUGFS echo -n 'func l2cap_retrans_timeout +p' > $DEBUGFS echo -n 'func l2cap_busy_work +p' > $DEBUGFS echo -n 'func l2cap_push_rx_skb +p' > $DEBUGFS echo -n 'func l2cap_data_channel_iframe +p' > $DEBUGFS echo -n 'func l2cap_data_channel_rrframe +p' > $DEBUGFS echo -n 'func l2cap_data_channel_rejframe +p' > $DEBUGFS echo -n 'func l2cap_data_channel_srejframe +p' > $DEBUGFS echo -n 'func l2cap_data_channel_rnrframe +p' > $DEBUGFS Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 1e39d72b80af..6e8a0512a9c9 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1314,6 +1314,8 @@ static void l2cap_monitor_timeout(unsigned long arg) { struct sock *sk = (void *) arg; + BT_DBG("sk %p", sk); + 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, ECONNABORTED); @@ -1332,6 +1334,8 @@ static void l2cap_retrans_timeout(unsigned long arg) { struct sock *sk = (void *) arg; + BT_DBG("sk %p", sk); + bh_lock_sock(sk); l2cap_pi(sk)->retry_count = 1; __mod_monitor_timer(); @@ -3645,6 +3649,8 @@ done: pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; pi->conn_state &= ~L2CAP_CONN_RNR_SENT; + BT_DBG("sk %p, Exit local busy", sk); + set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); @@ -3669,6 +3675,8 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) } /* Busy Condition */ + BT_DBG("sk %p, Enter local busy", sk); + pi->conn_state |= L2CAP_CONN_LOCAL_BUSY; bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; __skb_queue_tail(BUSY_QUEUE(sk), skb); @@ -3847,7 +3855,8 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str int num_to_ack = (pi->tx_win/6) + 1; int err = 0; - BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + BT_DBG("sk %p len %d tx_seq %d rx_control 0x%4.4x", sk, skb->len, tx_seq, + rx_control); if (L2CAP_CTRL_FINAL & rx_control && l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { @@ -3892,6 +3901,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str pi->buffer_seq = pi->buffer_seq_srej; pi->conn_state &= ~L2CAP_CONN_SREJ_SENT; l2cap_send_ack(pi); + BT_DBG("sk %p, Exit SREJ_SENT", sk); } } else { struct srej_list *l; @@ -3920,6 +3930,8 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str pi->conn_state |= L2CAP_CONN_SREJ_SENT; + BT_DBG("sk %p, Enter SREJ", sk); + INIT_LIST_HEAD(SREJ_LIST(sk)); pi->buffer_seq_srej = pi->buffer_seq; @@ -3973,6 +3985,9 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) { struct l2cap_pinfo *pi = l2cap_pi(sk); + BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control), + rx_control); + pi->expected_ack_seq = __get_reqseq(rx_control); l2cap_drop_acked_frames(sk); @@ -4018,6 +4033,8 @@ static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control) struct l2cap_pinfo *pi = l2cap_pi(sk); u8 tx_seq = __get_reqseq(rx_control); + BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; pi->expected_ack_seq = tx_seq; @@ -4040,6 +4057,8 @@ static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control) struct l2cap_pinfo *pi = l2cap_pi(sk); u8 tx_seq = __get_reqseq(rx_control); + BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; if (rx_control & L2CAP_CTRL_POLL) { @@ -4077,6 +4096,8 @@ static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control) struct l2cap_pinfo *pi = l2cap_pi(sk); u8 tx_seq = __get_reqseq(rx_control); + BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); + pi->conn_state |= L2CAP_CONN_REMOTE_BUSY; pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); -- cgit v1.2.3 From 64988868637304330f7df20d08b965592312c531 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 10 May 2010 14:54:14 -0300 Subject: Bluetooth: Tweaks to l2cap_send_i_or_rr_or_rnr() flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit l2cap_send_sframe() already set the F-bit if we set L2CAP_CONN_SEND_FBIT and unset L2CAP_CONN_SEND_FBIT after send the F-bit. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 6e8a0512a9c9..65c6a989449a 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3408,10 +3408,9 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { - control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL; + control |= L2CAP_SUPER_RCV_NOT_READY; l2cap_send_sframe(pi, control); pi->conn_state |= L2CAP_CONN_RNR_SENT; - pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; } if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY) -- cgit v1.2.3 From 85eb53c6f719523dde9e0658823dffd2664d4d1c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 3 Jun 2010 18:43:28 -0300 Subject: Bluetooth: Change the way we set ERTM mode as mandatory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the socket type is SOCK_STREAM we set Enhanced Retransmisson Mode or Streaming Mode as mandatory. That means that we will close the channel if the other side doesn't support or request the the mandatory mode. Basic mode can't be set as mandatory. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 65c6a989449a..e78a7504d09c 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -831,6 +831,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->imtu = l2cap_pi(parent)->imtu; pi->omtu = l2cap_pi(parent)->omtu; + pi->conf_state = l2cap_pi(parent)->conf_state; pi->mode = l2cap_pi(parent)->mode; pi->fcs = l2cap_pi(parent)->fcs; pi->max_tx = l2cap_pi(parent)->max_tx; @@ -841,10 +842,12 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) } else { pi->imtu = L2CAP_DEFAULT_MTU; pi->omtu = 0; - if (enable_ertm && sk->sk_type == SOCK_STREAM) + if (enable_ertm && sk->sk_type == SOCK_STREAM) { pi->mode = L2CAP_MODE_ERTM; - else + pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; + } else { pi->mode = L2CAP_MODE_BASIC; + } pi->max_tx = L2CAP_DEFAULT_MAX_TX; pi->fcs = L2CAP_FCS_CRC16; pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; @@ -1925,6 +1928,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us l2cap_pi(sk)->mode = opts.mode; switch (l2cap_pi(sk)->mode) { case L2CAP_MODE_BASIC: + l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: @@ -2469,7 +2473,12 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) switch (pi->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: - pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; + if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) { + pi->mode = l2cap_select_mode(rfc.mode, + pi->conn->feat_mask); + break; + } + if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); break; @@ -2602,7 +2611,12 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) switch (pi->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: - pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; + if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) { + pi->mode = l2cap_select_mode(rfc.mode, + pi->conn->feat_mask); + break; + } + if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) return -ECONNREFUSED; break; -- cgit v1.2.3 From 742e519b0db4a470008118b48f0baea6126e2122 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 8 Jun 2010 19:09:48 -0300 Subject: Bluetooth: Disconnect the channel if we don't want the proposed mode If the device is a STATE 2 then it should disconnect the channel if the remote device propose a mode different from its mandatory mode. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index e78a7504d09c..03e9125dd74f 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2617,8 +2617,9 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) break; } - if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) + if (pi->mode != rfc.mode) return -ECONNREFUSED; + break; default: pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); -- cgit v1.2.3 From ae12d52efd492ee6634c34322302ac754ff8cde8 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 8 Jun 2010 19:29:00 -0300 Subject: Bluetooth: Prefer Basic Mode on receipt of ConfigReq If we choose to use Basic Mode then we have to refuse the received mode and propose Basic Mode again. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 03e9125dd74f..ceed5df43fee 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2621,9 +2621,6 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) return -ECONNREFUSED; break; - default: - pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); - break; } done: -- cgit v1.2.3 From 625477523b4e656fbcc5ec2a8ca7a1beb39b1caf Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 8 Jun 2010 20:05:31 -0300 Subject: Bluetooth: Actively send request for Basic Mode The Profile Tuning Suite requires that we send a RFC containing the Basic Mode configuration when requesting Basic Mode. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index ceed5df43fee..ca9bab225777 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2492,6 +2492,14 @@ done: case L2CAP_MODE_BASIC: if (pi->imtu != L2CAP_DEFAULT_MTU) l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + + rfc.mode = L2CAP_MODE_BASIC; + rfc.txwin_size = 0; + rfc.max_transmit = 0; + rfc.retrans_timeout = 0; + rfc.monitor_timeout = 0; + rfc.max_pdu_size = 0; + break; case L2CAP_MODE_ERTM: @@ -2504,9 +2512,6 @@ done: if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); - l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, - sizeof(rfc), (unsigned long) &rfc); - if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) break; @@ -2527,9 +2532,6 @@ done: if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); - l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, - sizeof(rfc), (unsigned long) &rfc); - if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) break; @@ -2541,6 +2543,9 @@ done: break; } + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), + (unsigned long) &rfc); + /* FIXME: Need actual value of the flush timeout */ //if (flush_to != L2CAP_DEFAULT_FLUSH_TO) // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to); -- cgit v1.2.3 From 6c2ea7a8f5fea67fa20e5825401b8fce5a78dbf6 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 8 Jun 2010 20:08:49 -0300 Subject: Bluetooth: Refuse ConfigRsp with different mode If our mode is Basic Mode we have to refuse any ConfigRsp that proposes a different mode. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index ca9bab225777..c5904082392c 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2747,7 +2747,6 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, rfc.mode != pi->mode) return -ECONNREFUSED; - pi->mode = rfc.mode; pi->fcs = 0; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, @@ -2756,6 +2755,11 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, } } + if (pi->mode == L2CAP_MODE_BASIC && pi->mode != rfc.mode) + return -ECONNREFUSED; + + pi->mode = rfc.mode; + if (*result == L2CAP_CONF_SUCCESS) { switch (rfc.mode) { case L2CAP_MODE_ERTM: -- cgit v1.2.3 From 2ba13ed678775195e8255b4e503c59d48b615bd8 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 9 Jun 2010 16:39:05 -0300 Subject: Bluetooth: Remove check for supported mode Since now we have checks for the supported mode before on l2cap_info_rsp we can remove the check for it here. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c5904082392c..2fb45c481762 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2473,15 +2473,10 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) switch (pi->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: - if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) { - pi->mode = l2cap_select_mode(rfc.mode, - pi->conn->feat_mask); + if (pi->conf_state & L2CAP_CONF_STATE2_DEVICE) break; - } - if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); - break; + /* fall through */ default: pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); break; -- cgit v1.2.3 From cf6c2c0b9f47ee3cd12684b905725c8376d52135 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 7 Jun 2010 20:54:45 -0300 Subject: Bluetooth: Disconnect early if mode is not supported When mode is mandatory we shall not send connect request and report this to the userspace as well. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 5 ++++ net/bluetooth/l2cap.c | 56 ++++++++++++++++++++++++++++++------------- 2 files changed, 45 insertions(+), 16 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7c695bfd853c..f8bae5415438 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -287,6 +287,11 @@ struct l2cap_conn { struct l2cap_chan_list chan_list; }; +struct sock_del_list { + struct sock *sk; + struct list_head list; +}; + #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 #define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04 #define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08 diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 2fb45c481762..6a33d269389e 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -456,6 +456,22 @@ static void l2cap_do_start(struct sock *sk) } } +static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) +{ + u32 local_feat_mask = l2cap_feat_mask; + if (enable_ertm) + local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING; + + switch (mode) { + case L2CAP_MODE_ERTM: + return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask; + case L2CAP_MODE_STREAMING: + return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask; + default: + return 0x00; + } +} + static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) { struct l2cap_disconn_req req; @@ -484,10 +500,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int static void l2cap_conn_start(struct l2cap_conn *conn) { struct l2cap_chan_list *l = &conn->chan_list; + struct sock_del_list del, *tmp1, *tmp2; struct sock *sk; BT_DBG("conn %p", conn); + INIT_LIST_HEAD(&del.list); + read_lock(&l->lock); for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { @@ -503,6 +522,19 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (l2cap_check_security(sk) && __l2cap_no_conn_pending(sk)) { struct l2cap_conn_req req; + + if (!l2cap_mode_supported(l2cap_pi(sk)->mode, + conn->feat_mask) + && l2cap_pi(sk)->conf_state & + L2CAP_CONF_STATE2_DEVICE) { + tmp1 = kzalloc(sizeof(struct srej_list), + GFP_ATOMIC); + tmp1->sk = sk; + list_add_tail(&tmp1->list, &del.list); + bh_unlock_sock(sk); + continue; + } + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; @@ -542,6 +574,14 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } read_unlock(&l->lock); + + list_for_each_entry_safe(tmp1, tmp2, &del.list, list) { + bh_lock_sock(tmp1->sk); + __l2cap_sock_close(tmp1->sk, ECONNRESET); + bh_unlock_sock(tmp1->sk); + list_del(&tmp1->list); + kfree(tmp1); + } } static void l2cap_conn_ready(struct l2cap_conn *conn) @@ -2429,22 +2469,6 @@ static inline void l2cap_ertm_init(struct sock *sk) INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); } -static int l2cap_mode_supported(__u8 mode, __u32 feat_mask) -{ - u32 local_feat_mask = l2cap_feat_mask; - if (enable_ertm) - local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING; - - switch (mode) { - case L2CAP_MODE_ERTM: - return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask; - case L2CAP_MODE_STREAMING: - return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask; - default: - return 0x00; - } -} - static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) { switch (mode) { -- cgit v1.2.3 From 8cb8e6f1684be13b51f8429b15f39c140326b327 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 14 Jun 2010 02:26:15 -0300 Subject: Bluetooth: Don't accept ConfigReq if we aren't in the BT_CONFIG state If such event happens we shall reply with a Command Reject, because we are not expecting any configure request. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 6a33d269389e..f6e46fdddd2b 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3052,8 +3052,14 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!sk) return -ENOENT; - if (sk->sk_state == BT_DISCONN) + if (sk->sk_state != BT_CONFIG) { + struct l2cap_cmd_rej rej; + + rej.reason = cpu_to_le16(0x0002); + l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ, + sizeof(rej), &rej); goto unlock; + } /* Reject if config buffer is too small. */ len = cmd_len - sizeof(*req); -- cgit v1.2.3 From e0f66218b3a7d0bcf37ca95186123c257fda0ba5 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 21 Jun 2010 18:50:49 -0300 Subject: Bluetooth: Remove the send_lock spinlock from ERTM Using a lock to deal with the ERTM race condition - interruption with new data from the hci layer - is wrong. We should use the native skb backlog queue. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap.c | 28 +--------------------------- 2 files changed, 1 insertion(+), 28 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f8bae5415438..7df70e47c878 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -358,7 +358,6 @@ struct l2cap_pinfo { __le16 sport; - spinlock_t send_lock; struct timer_list retrans_timer; struct timer_list monitor_timer; struct timer_list ack_timer; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index f6e46fdddd2b..dc8601fc2404 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1562,16 +1562,11 @@ static int l2cap_retransmit_frames(struct sock *sk) struct l2cap_pinfo *pi = l2cap_pi(sk); int ret; - spin_lock_bh(&pi->send_lock); - if (!skb_queue_empty(TX_QUEUE(sk))) sk->sk_send_head = TX_QUEUE(sk)->next; pi->next_tx_seq = pi->expected_ack_seq; ret = l2cap_ertm_send(sk); - - spin_unlock_bh(&pi->send_lock); - return ret; } @@ -1579,7 +1574,6 @@ static void l2cap_send_ack(struct l2cap_pinfo *pi) { struct sock *sk = (struct sock *)pi; u16 control = 0; - int nframes; control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; @@ -1590,11 +1584,7 @@ static void l2cap_send_ack(struct l2cap_pinfo *pi) return; } - spin_lock_bh(&pi->send_lock); - nframes = l2cap_ertm_send(sk); - spin_unlock_bh(&pi->send_lock); - - if (nframes > 0) + if (l2cap_ertm_send(sk) > 0) return; control |= L2CAP_SUPER_RCV_READY; @@ -1789,10 +1779,8 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz size += buflen; } skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk)); - spin_lock_bh(&pi->send_lock); if (sk->sk_send_head == NULL) sk->sk_send_head = sar_queue.next; - spin_unlock_bh(&pi->send_lock); return size; } @@ -1864,14 +1852,9 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms } __skb_queue_tail(TX_QUEUE(sk), skb); - if (pi->mode == L2CAP_MODE_ERTM) - spin_lock_bh(&pi->send_lock); - if (sk->sk_send_head == NULL) sk->sk_send_head = skb; - if (pi->mode == L2CAP_MODE_ERTM) - spin_unlock_bh(&pi->send_lock); } else { /* Segment SDU into multiples PDUs */ err = l2cap_sar_segment_sdu(sk, msg, len); @@ -1887,9 +1870,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms err = len; break; } - spin_lock_bh(&pi->send_lock); err = l2cap_ertm_send(sk); - spin_unlock_bh(&pi->send_lock); } if (err >= 0) @@ -2464,7 +2445,6 @@ static inline void l2cap_ertm_init(struct sock *sk) __skb_queue_head_init(SREJ_QUEUE(sk)); __skb_queue_head_init(BUSY_QUEUE(sk)); - spin_lock_init(&l2cap_pi(sk)->send_lock); INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); } @@ -3462,9 +3442,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY) l2cap_retransmit_frames(sk); - spin_lock_bh(&pi->send_lock); l2cap_ertm_send(sk); - spin_unlock_bh(&pi->send_lock); if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) && pi->frames_sent == 0) { @@ -4066,9 +4044,7 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { l2cap_send_ack(pi); } else { - spin_lock_bh(&pi->send_lock); l2cap_ertm_send(sk); - spin_unlock_bh(&pi->send_lock); } } } @@ -4113,9 +4089,7 @@ static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control) pi->conn_state |= L2CAP_CONN_SEND_FBIT; l2cap_retransmit_one_frame(sk, tx_seq); - spin_lock_bh(&pi->send_lock); l2cap_ertm_send(sk); - spin_unlock_bh(&pi->send_lock); if (pi->conn_state & L2CAP_CONN_WAIT_F) { pi->srej_save_reqseq = tx_seq; -- cgit v1.2.3 From 218bb9dfd21472128f86b38ad2eab123205c2991 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 21 Jun 2010 18:53:22 -0300 Subject: Bluetooth: Add backlog queue to ERTM code backlog queue is the canonical mechanism to avoid race conditions due interrupts in bottom half context. After the socket lock is released the net core take care of push all skb in its backlog queue. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 132 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 53 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index dc8601fc2404..cf4481f7f566 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -77,6 +77,8 @@ static void l2cap_sock_kill(struct sock *sk); static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, u8 ident, u16 dlen, void *data); +static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); + /* ---- L2CAP timers ---- */ static void l2cap_sock_timeout(unsigned long arg) { @@ -2447,6 +2449,8 @@ static inline void l2cap_ertm_init(struct sock *sk) __skb_queue_head_init(BUSY_QUEUE(sk)); INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); + + sk->sk_backlog_rcv = l2cap_ertm_data_rcv; } static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) @@ -4171,13 +4175,83 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str return 0; } +static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + u16 control; + u8 req_seq; + int len, next_tx_seq_offset, req_seq_offset; + + control = get_unaligned_le16(skb->data); + skb_pull(skb, 2); + len = skb->len; + + /* + * We can just drop the corrupted I-frame here. + * Receiver will miss it and start proper recovery + * procedures and ask retransmission. + */ + if (l2cap_check_fcs(pi, skb)) + goto drop; + + if (__is_sar_start(control) && __is_iframe(control)) + len -= 2; + + if (pi->fcs == L2CAP_FCS_CRC16) + len -= 2; + + if (len > pi->mps) { + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + goto drop; + } + + req_seq = __get_reqseq(control); + req_seq_offset = (req_seq - pi->expected_ack_seq) % 64; + if (req_seq_offset < 0) + req_seq_offset += 64; + + next_tx_seq_offset = + (pi->next_tx_seq - pi->expected_ack_seq) % 64; + if (next_tx_seq_offset < 0) + next_tx_seq_offset += 64; + + /* check for invalid req-seq */ + if (req_seq_offset > next_tx_seq_offset) { + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + goto drop; + } + + if (__is_iframe(control)) { + if (len < 0) { + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + goto drop; + } + + l2cap_data_channel_iframe(sk, control, skb); + } else { + if (len != 0) { + BT_ERR("%d", len); + l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + goto drop; + } + + l2cap_data_channel_sframe(sk, control, skb); + } + + return 0; + +drop: + kfree_skb(skb); + return 0; +} + static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { struct sock *sk; struct l2cap_pinfo *pi; u16 control; - u8 tx_seq, req_seq; - int len, next_tx_seq_offset, req_seq_offset; + u8 tx_seq; + int len; sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); if (!sk) { @@ -4207,59 +4281,11 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk break; case L2CAP_MODE_ERTM: - control = get_unaligned_le16(skb->data); - skb_pull(skb, 2); - len = skb->len; - - /* - * We can just drop the corrupted I-frame here. - * Receiver will miss it and start proper recovery - * procedures and ask retransmission. - */ - if (l2cap_check_fcs(pi, skb)) - goto drop; - - if (__is_sar_start(control) && __is_iframe(control)) - len -= 2; - - if (pi->fcs == L2CAP_FCS_CRC16) - len -= 2; - - if (len > pi->mps) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); - goto drop; - } - - req_seq = __get_reqseq(control); - req_seq_offset = (req_seq - pi->expected_ack_seq) % 64; - if (req_seq_offset < 0) - req_seq_offset += 64; - - next_tx_seq_offset = - (pi->next_tx_seq - pi->expected_ack_seq) % 64; - if (next_tx_seq_offset < 0) - next_tx_seq_offset += 64; - - /* check for invalid req-seq */ - if (req_seq_offset > next_tx_seq_offset) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); - goto drop; - } - - if (__is_iframe(control)) { - if (len < 0) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); - goto drop; - } - - l2cap_data_channel_iframe(sk, control, skb); + if (!sock_owned_by_user(sk)) { + l2cap_ertm_data_rcv(sk, skb); } else { - if (len != 0) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + if (sk_add_backlog(sk, skb)) goto drop; - } - - l2cap_data_channel_sframe(sk, control, skb); } goto done; -- cgit v1.2.3 From 712132eb541e4a76afad97898dc0ce6b6c0032d8 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 21 Jun 2010 19:39:50 -0300 Subject: Bluetooth: Improve ERTM local busy handling Now we also check if can push skb userspace just after receive a new skb instead of only wait the l2cap_busy_work wake up from time to time to check the local busy condition. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 83 +++++++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 36 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index cf4481f7f566..6b839d682143 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3606,6 +3606,46 @@ disconnect: return 0; } +static int l2cap_try_push_rx_skb(struct sock *sk) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *skb; + u16 control; + int err; + + while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) { + control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; + err = l2cap_ertm_reassembly_sdu(sk, skb, control); + if (err < 0) { + skb_queue_head(BUSY_QUEUE(sk), skb); + return -EBUSY; + } + + pi->buffer_seq = (pi->buffer_seq + 1) % 64; + } + + if (!(pi->conn_state & L2CAP_CONN_RNR_SENT)) + goto done; + + control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; + l2cap_send_sframe(pi, control); + l2cap_pi(sk)->retry_count = 1; + + del_timer(&pi->retrans_timer); + __mod_monitor_timer(); + + l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; + +done: + pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; + pi->conn_state &= ~L2CAP_CONN_RNR_SENT; + + BT_DBG("sk %p, Exit local busy", sk); + + return 0; +} + static void l2cap_busy_work(struct work_struct *work) { DECLARE_WAITQUEUE(wait, current); @@ -3614,7 +3654,6 @@ static void l2cap_busy_work(struct work_struct *work) struct sock *sk = (struct sock *)pi; int n_tries = 0, timeo = HZ/5, err; struct sk_buff *skb; - u16 control; lock_sock(sk); @@ -3625,7 +3664,7 @@ static void l2cap_busy_work(struct work_struct *work) if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { err = -EBUSY; l2cap_send_disconn_req(pi->conn, sk, EBUSY); - goto done; + break; } if (!timeo) @@ -3633,7 +3672,7 @@ static void l2cap_busy_work(struct work_struct *work) if (signal_pending(current)) { err = sock_intr_errno(timeo); - goto done; + break; } release_sock(sk); @@ -3642,42 +3681,12 @@ static void l2cap_busy_work(struct work_struct *work) err = sock_error(sk); if (err) - goto done; - - while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) { - control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; - err = l2cap_ertm_reassembly_sdu(sk, skb, control); - if (err < 0) { - skb_queue_head(BUSY_QUEUE(sk), skb); - break; - } - - pi->buffer_seq = (pi->buffer_seq + 1) % 64; - } + break; - if (!skb) + if (l2cap_try_push_rx_skb(sk) == 0) break; } - if (!(pi->conn_state & L2CAP_CONN_RNR_SENT)) - goto done; - - control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; - control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; - l2cap_send_sframe(pi, control); - l2cap_pi(sk)->retry_count = 1; - - del_timer(&pi->retrans_timer); - __mod_monitor_timer(); - - l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; - -done: - pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; - pi->conn_state &= ~L2CAP_CONN_RNR_SENT; - - BT_DBG("sk %p, Exit local busy", sk); - set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); @@ -3692,7 +3701,9 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; __skb_queue_tail(BUSY_QUEUE(sk), skb); - return -EBUSY; + return l2cap_try_push_rx_skb(sk); + + } err = l2cap_ertm_reassembly_sdu(sk, skb, control); -- cgit v1.2.3 From 8b0dc6dc827fb71efd6c9dfb5c4172b7b5c96cee Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Tue, 22 Jun 2010 13:56:22 -0300 Subject: Bluetooth: Fix l2cap_sock_connect error return. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return a proper error value if socket is already connected. Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 6b839d682143..e322be8ff948 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1158,6 +1158,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al case BT_CONNECTED: /* Already connected */ + err = -EISCONN; goto done; case BT_OPEN: -- cgit v1.2.3 From 305682e8377b0f560d4b885c169a72e6a62331e9 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Tue, 22 Jun 2010 13:56:23 -0300 Subject: Bluetooth: Make l2cap_streaming_send() void. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It doesn't make sense to have a return value since we always set it to 0. Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index e322be8ff948..33e134b0d402 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1420,7 +1420,7 @@ static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb) hci_send_acl(pi->conn->hcon, skb, 0); } -static int l2cap_streaming_send(struct sock *sk) +static void l2cap_streaming_send(struct sock *sk) { struct sk_buff *skb, *tx_skb; struct l2cap_pinfo *pi = l2cap_pi(sk); @@ -1450,7 +1450,6 @@ static int l2cap_streaming_send(struct sock *sk) skb = skb_dequeue(TX_QUEUE(sk)); kfree_skb(skb); } - return 0; } static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) @@ -1866,7 +1865,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms } if (pi->mode == L2CAP_MODE_STREAMING) { - err = l2cap_streaming_send(sk); + l2cap_streaming_send(sk); } else { if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->conn_state && L2CAP_CONN_WAIT_F) { -- cgit v1.2.3 From f9dd11b03c5c3cd6bdf2e503400bbc922c898974 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Tue, 22 Jun 2010 13:56:24 -0300 Subject: Bluetooth: Fix error return value on sendmsg. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we try to send a message bigger than the outgoing MTU value EMSGSIZE (message too long) should be returned. Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 33e134b0d402..884b840081ae 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1827,7 +1827,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms case L2CAP_MODE_BASIC: /* Check outgoing MTU */ if (len > pi->omtu) { - err = -EINVAL; + err = -EMSGSIZE; goto done; } -- cgit v1.2.3 From bc766db2ef3700ae74bdfc88d74b771b97971a24 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Tue, 22 Jun 2010 13:56:25 -0300 Subject: Bluetooth: Fix error return value on sendmsg. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the socket is in a bad state EBADFD is more appropriate then EINVAL. Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 884b840081ae..ac25952538fd 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1881,7 +1881,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms default: BT_DBG("bad state %1.1x", pi->mode); - err = -EINVAL; + err = -EBADFD; } done: -- cgit v1.2.3 From 57d3b22bf56579bb1ab2d6f5020d372c99a7afae Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Tue, 22 Jun 2010 13:56:26 -0300 Subject: Bluetooth: Fix error return for l2cap_connect_rsp(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index ac25952538fd..58c81cbb4040 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2986,11 +2986,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd if (scid) { sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); if (!sk) - return 0; + return -EFAULT; } else { sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); if (!sk) - return 0; + return -EFAULT; } switch (result) { -- cgit v1.2.3 From 7a560e5c99dc5f03e2c0dbe05ed20008af5d0bcf Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Tue, 22 Jun 2010 13:56:27 -0300 Subject: Bluetooth: Fix error value for wrong FCS. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 58c81cbb4040..de545f1687d8 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3423,7 +3423,7 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size); if (our_fcs != rcv_fcs) - return -EINVAL; + return -EBADMSG; } return 0; } -- cgit v1.2.3 From 963cf687e825f7a59817f145a1ea19bdc224a18f Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Tue, 22 Jun 2010 13:56:28 -0300 Subject: Bluetooth: Fix error return on L2CAP-HCI interface. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L2CAP only deals with ACL links. EINVAL should be returned otherwise. Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index de545f1687d8..a3dfee97ab9d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -4415,7 +4415,7 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) struct hlist_node *node; if (type != ACL_LINK) - return 0; + return -EINVAL; BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); @@ -4448,7 +4448,7 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); if (hcon->type != ACL_LINK) - return 0; + return -EINVAL; if (!status) { conn = l2cap_conn_add(hcon, status); @@ -4477,7 +4477,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) BT_DBG("hcon %p reason %d", hcon, reason); if (hcon->type != ACL_LINK) - return 0; + return -EINVAL; l2cap_conn_del(hcon, bt_err(reason)); -- cgit v1.2.3 From e9aeb2ddd441f0c8699ff04c499d7213730a0f04 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 8 Jul 2010 20:08:18 -0300 Subject: Bluetooth: Send ConfigReq after send a ConnectionRsp The extended L2CAP features requires that one should initiate a ConfigReq after send the ConnectionRsp. This patch changes the behaviour of the configuration process of our stack. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index a3dfee97ab9d..e366be0792cb 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -74,6 +74,7 @@ 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); +static int l2cap_build_conf_req(struct sock *sk, void *data); static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, u8 ident, u16 dlen, void *data); @@ -548,6 +549,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } } else if (sk->sk_state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; + char buf[128]; rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); @@ -570,6 +572,17 @@ static void l2cap_conn_start(struct l2cap_conn *conn) l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); + + if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT || + rsp.result != L2CAP_CR_SUCCESS) { + bh_unlock_sock(sk); + continue; + } + + l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, + l2cap_build_conf_req(sk, buf), buf); + l2cap_pi(sk)->num_conf_req++; } bh_unlock_sock(sk); @@ -1897,6 +1910,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { struct l2cap_conn_rsp rsp; + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + u8 buf[128]; sk->sk_state = BT_CONFIG; @@ -1907,6 +1922,16 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); + if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) { + release_sock(sk); + return 0; + } + + l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, + l2cap_build_conf_req(sk, buf), buf); + l2cap_pi(sk)->num_conf_req++; + release_sock(sk); return 0; } @@ -2613,7 +2638,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) } } - if (pi->num_conf_rsp || pi->num_conf_req) + if (pi->num_conf_rsp || pi->num_conf_req > 1) goto done; switch (pi->mode) { @@ -2857,7 +2882,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd struct l2cap_chan_list *list = &conn->chan_list; struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; - struct sock *sk, *parent; + struct sock *parent, *uninitialized_var(sk); int result, status = L2CAP_CS_NO_INFO; u16 dcid = 0, scid = __le16_to_cpu(req->scid); @@ -2966,6 +2991,15 @@ sendresp: L2CAP_INFO_REQ, sizeof(info), &info); } + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) && + result == L2CAP_CR_SUCCESS) { + u8 buf[128]; + l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, + l2cap_build_conf_req(sk, buf), buf); + l2cap_pi(sk)->num_conf_req++; + } + return 0; } @@ -2998,9 +3032,13 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd sk->sk_state = BT_CONFIG; l2cap_pi(sk)->ident = 0; l2cap_pi(sk)->dcid = dcid; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND; + if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) + break; + + l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); l2cap_pi(sk)->num_conf_req++; -- cgit v1.2.3 From 89746b856c88af9e5019e84615d88e002fb54dc3 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 9 Jul 2010 16:38:34 -0300 Subject: Bluetooth: Fix bug in kzalloc allocation size Probably a typo error. We were using the wrong struct to get size. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index e366be0792cb..419e2c3306aa 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -530,7 +530,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) conn->feat_mask) && l2cap_pi(sk)->conf_state & L2CAP_CONF_STATE2_DEVICE) { - tmp1 = kzalloc(sizeof(struct srej_list), + tmp1 = kzalloc(sizeof(struct sock_del_list), GFP_ATOMIC); tmp1->sk = sk; list_add_tail(&tmp1->list, &del.list); -- cgit v1.2.3 From 47731de789749c9ed3c54751db28fd9c9eeaf019 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 9 Jul 2010 16:38:35 -0300 Subject: Bluetooth: Keep code under column 80 Purely a cosmetic change, it doesn't change the code flow. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 419e2c3306aa..449cbdd4ddbb 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -522,31 +522,35 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } if (sk->sk_state == BT_CONNECT) { - if (l2cap_check_security(sk) && - __l2cap_no_conn_pending(sk)) { - struct l2cap_conn_req req; + struct l2cap_conn_req req; - if (!l2cap_mode_supported(l2cap_pi(sk)->mode, - conn->feat_mask) - && l2cap_pi(sk)->conf_state & - L2CAP_CONF_STATE2_DEVICE) { - tmp1 = kzalloc(sizeof(struct sock_del_list), - GFP_ATOMIC); - tmp1->sk = sk; - list_add_tail(&tmp1->list, &del.list); - bh_unlock_sock(sk); - continue; - } + if (!l2cap_check_security(sk) || + !__l2cap_no_conn_pending(sk)) { + bh_unlock_sock(sk); + continue; + } - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; + if (!l2cap_mode_supported(l2cap_pi(sk)->mode, + conn->feat_mask) + && l2cap_pi(sk)->conf_state & + L2CAP_CONF_STATE2_DEVICE) { + tmp1 = kzalloc(sizeof(struct sock_del_list), + GFP_ATOMIC); + tmp1->sk = sk; + list_add_tail(&tmp1->list, &del.list); + bh_unlock_sock(sk); + continue; + } - l2cap_pi(sk)->ident = l2cap_get_ident(conn); - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; + + l2cap_pi(sk)->ident = l2cap_get_ident(conn); + l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + + l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + L2CAP_CONN_REQ, sizeof(req), &req); - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_REQ, sizeof(req), &req); - } } else if (sk->sk_state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; char buf[128]; -- cgit v1.2.3 From ce5706bd69be6b25715ed6cd48a210b5080032bc Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 13 Jul 2010 11:57:11 -0300 Subject: Bluetooth: Add Copyright notice to L2CAP Copyright for the time I worked on L2CAP during the Google Summer of Code program. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap.c | 1 + 2 files changed, 2 insertions(+) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7df70e47c878..d0303021aba7 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -1,6 +1,7 @@ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated + Copyright (C) 2009-2010 Gustavo F. Padovan Written 2000,2001 by Maxim Krasnyansky diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 449cbdd4ddbb..67a6f59873aa 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1,6 +1,7 @@ /* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated + Copyright (C) 2009-2010 Gustavo F. Padovan Written 2000,2001 by Maxim Krasnyansky -- cgit v1.2.3 From dd135240e8e10295f7e7cdf347800df6e1841437 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 13 Jul 2010 11:57:12 -0300 Subject: Bluetooth: Update L2CAP version information We did some changes on the L2CAP configuration process and its behaviour is bit different now. That justifies a updated on the L2CAP version. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 67a6f59873aa..cdd608d72741 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -54,7 +54,7 @@ #include #include -#define VERSION "2.14" +#define VERSION "2.15" static int enable_ertm = 0; -- cgit v1.2.3 From 5d8868ff3d11e3fc5a5c07477f281a16c71714a3 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 16 Jul 2010 16:18:39 -0300 Subject: Bluetooth: Add Google's copyright to L2CAP Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap.c | 1 + 2 files changed, 2 insertions(+) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d0303021aba7..4b86c783976c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -2,6 +2,7 @@ BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated Copyright (C) 2009-2010 Gustavo F. Padovan + Copyright (C) 2010 Google Inc. Written 2000,2001 by Maxim Krasnyansky diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index cdd608d72741..d175cc262833 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2,6 +2,7 @@ BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated Copyright (C) 2009-2010 Gustavo F. Padovan + Copyright (C) 2010 Google Inc. Written 2000,2001 by Maxim Krasnyansky -- cgit v1.2.3 From d1c4a17d58a6dfacb48935aa430aa986559a885f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sun, 18 Jul 2010 16:25:54 -0300 Subject: Bluetooth: Enable L2CAP Extended features by default Change the enable_ertm param to disable_ertm and default value to 0. That means that L2CAP Extended features are enabled by default now. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index d175cc262833..9ba1e8eee37c 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -57,7 +57,7 @@ #define VERSION "2.15" -static int enable_ertm = 0; +static int disable_ertm = 0; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; static u8 l2cap_fixed_chan[8] = { 0x02, }; @@ -464,7 +464,7 @@ static void l2cap_do_start(struct sock *sk) static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) { u32 local_feat_mask = l2cap_feat_mask; - if (enable_ertm) + if (!disable_ertm) local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING; switch (mode) { @@ -903,7 +903,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) } else { pi->imtu = L2CAP_DEFAULT_MTU; pi->omtu = 0; - if (enable_ertm && sk->sk_type == SOCK_STREAM) { + if (!disable_ertm && sk->sk_type == SOCK_STREAM) { pi->mode = L2CAP_MODE_ERTM; pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; } else { @@ -1160,7 +1160,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: - if (enable_ertm) + if (!disable_ertm) break; /* fall through */ default: @@ -1226,7 +1226,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: - if (enable_ertm) + if (!disable_ertm) break; /* fall through */ default: @@ -1986,7 +1986,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: - if (enable_ertm) + if (!disable_ertm) break; /* fall through */ default: @@ -3302,7 +3302,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf; rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK); rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); - if (enable_ertm) + if (!disable_ertm) feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING | L2CAP_FEAT_FCS; put_unaligned_le32(feat_mask, rsp->data); @@ -4850,8 +4850,8 @@ EXPORT_SYMBOL(l2cap_load); module_init(l2cap_init); module_exit(l2cap_exit); -module_param(enable_ertm, bool, 0644); -MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode"); +module_param(disable_ertm, bool, 0644); +MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode"); MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); -- cgit v1.2.3