From aa395145165cb06a0d0885221bbe0ce4a564391d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 20 Apr 2010 13:03:51 +0000 Subject: net: sk_sleep() helper Define a new function to return the waitqueue of a "struct sock". static inline wait_queue_head_t *sk_sleep(struct sock *sk) { return sk->sk_sleep; } Change all read occurrences of sk_sleep by a call to this function. Needed for a future RCU conversion. sk_sleep wont be a field directly available. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- 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 99d68c34e4f..c1e60eed5a9 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1147,7 +1147,7 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl BT_DBG("sk %p timeo %ld", sk, timeo); /* Wait for an incoming connection. (wake-one). */ - add_wait_queue_exclusive(sk->sk_sleep, &wait); + add_wait_queue_exclusive(sk_sleep(sk), &wait); while (!(nsk = bt_accept_dequeue(sk, newsock))) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) { @@ -1170,7 +1170,7 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl } } set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sk_sleep, &wait); + remove_wait_queue(sk_sleep(sk), &wait); if (err) goto done; -- cgit v1.2.3-70-g09d2 From c69163e9ed5048407cc84f439cbfecc53f6f7131 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:35 -0300 Subject: Bluetooth: Move specific Basic Mode code to the right place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inside "case L2CAP_MODE_BASIC:" we don't need to check for sk_type and L2CAP mode. So only the length check is fine. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 864c76f4a67..c9a848d3ef9 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1611,11 +1611,6 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; - /* Check outgoing MTU */ - if (sk->sk_type == SOCK_SEQPACKET && pi->mode == L2CAP_MODE_BASIC && - len > pi->omtu) - return -EINVAL; - lock_sock(sk); if (sk->sk_state != BT_CONNECTED) { @@ -1635,6 +1630,12 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms switch (pi->mode) { case L2CAP_MODE_BASIC: + /* Check outgoing MTU */ + if (len > pi->omtu) { + err = -EINVAL; + goto done; + } + /* Create a basic PDU */ skb = l2cap_create_basic_pdu(sk, msg, len); if (IS_ERR(skb)) { -- cgit v1.2.3-70-g09d2 From faaebd192ec9c3febcab98149d1309199a5b886c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:35 -0300 Subject: Bluetooth: Fix memory leak of S-frames into L2CAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit l2cap_data_channel do not free the S-frame, so we free it here. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita 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 c9a848d3ef9..46f22640a33 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3522,6 +3522,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str break; } + kfree_skb(skb); return 0; } -- cgit v1.2.3-70-g09d2 From 7dffe4210233a2860c3f41477c40b3252edf2b7d Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:36 -0300 Subject: Bluetooth: Fix expected_tx_seq calculation on L2CAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All operation related to the txWindow should be modulo 64. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita 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 46f22640a33..401011a53c7 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3611,7 +3611,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (pi->expected_tx_seq == tx_seq) pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; else - pi->expected_tx_seq = tx_seq + 1; + pi->expected_tx_seq = (tx_seq + 1) % 64; l2cap_sar_reassembly_sdu(sk, skb, control); -- cgit v1.2.3-70-g09d2 From d1daa091e8612f3aab14d28b5836375fafe155e1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:36 -0300 Subject: Bluetooth: Fix ACL MTU issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ERTM and Streaming Modes was having problems when the ACL MTU is lower than MPS. The 'minus 10' is to take in account the header and fcs lenghts. 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 401011a53c7..99cf1772b48 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2267,6 +2267,8 @@ done: rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); + if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) + rfc.max_pdu_size = pi->conn->mtu - 10; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -2288,6 +2290,8 @@ done: rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); + if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) + rfc.max_pdu_size = pi->conn->mtu - 10; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); -- cgit v1.2.3-70-g09d2 From e8235c6bdd1c7ffbaa7eb8dcdbb46c51f1e5d72e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:36 -0300 Subject: Bluetooth: Use a l2cap_pinfo struct instead l2cap_pi() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trivial clean up. 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 99cf1772b48..a9c152a09f0 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1291,7 +1291,7 @@ static int l2cap_streaming_send(struct sock *sk) control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); - if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) { + if (pi->fcs == L2CAP_FCS_CRC16) { fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); } @@ -1344,7 +1344,7 @@ static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq) | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); - if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) { + if (pi->fcs == L2CAP_FCS_CRC16) { fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); } @@ -1388,7 +1388,7 @@ static int l2cap_ertm_send(struct sock *sk) put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); - if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) { + if (pi->fcs == L2CAP_FCS_CRC16) { fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2); put_unaligned_le16(fcs, skb->data + tx_skb->len - 2); } @@ -3518,10 +3518,10 @@ 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); - del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&pi->retrans_timer); if (rx_control & L2CAP_CTRL_POLL) { u16 control = L2CAP_CTRL_FINAL; - l2cap_send_rr_or_rnr(l2cap_pi(sk), control); + l2cap_send_rr_or_rnr(pi, control); } break; } @@ -3622,7 +3622,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk goto done; default: - BT_DBG("sk %p: bad mode 0x%2.2x", sk, l2cap_pi(sk)->mode); + BT_DBG("sk %p: bad mode 0x%2.2x", sk, pi->mode); break; } -- cgit v1.2.3-70-g09d2 From d5392c8f1e9faef089bb7cb66c3314da8bddd1fe Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:36 -0300 Subject: Bluetooth: Implement 'Send IorRRorRNR' event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After receive a RR with P bit set ERTM shall use this funcion to choose what type of frame to reply with F bit = 1. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 20 +++++++++++--------- net/bluetooth/l2cap.c | 43 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 13 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 17a689f27a6..d9c20c3d6f3 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -320,7 +320,7 @@ struct l2cap_pinfo { __u8 conf_req[64]; __u8 conf_len; __u8 conf_state; - __u8 conn_state; + __u16 conn_state; __u8 next_tx_seq; __u8 expected_ack_seq; @@ -328,6 +328,7 @@ struct l2cap_pinfo { __u8 buffer_seq; __u8 buffer_seq_srej; __u8 srej_save_reqseq; + __u8 frames_sent; __u8 unacked_frames; __u8 retry_count; __u8 num_to_ack; @@ -367,14 +368,15 @@ struct l2cap_pinfo { #define L2CAP_CONF_MAX_CONF_REQ 2 #define L2CAP_CONF_MAX_CONF_RSP 2 -#define L2CAP_CONN_SAR_SDU 0x01 -#define L2CAP_CONN_SREJ_SENT 0x02 -#define L2CAP_CONN_WAIT_F 0x04 -#define L2CAP_CONN_SREJ_ACT 0x08 -#define L2CAP_CONN_SEND_PBIT 0x10 -#define L2CAP_CONN_REMOTE_BUSY 0x20 -#define L2CAP_CONN_LOCAL_BUSY 0x40 -#define L2CAP_CONN_REJ_ACT 0x80 +#define L2CAP_CONN_SAR_SDU 0x0001 +#define L2CAP_CONN_SREJ_SENT 0x0002 +#define L2CAP_CONN_WAIT_F 0x0004 +#define L2CAP_CONN_SREJ_ACT 0x0008 +#define L2CAP_CONN_SEND_PBIT 0x0010 +#define L2CAP_CONN_REMOTE_BUSY 0x0020 +#define L2CAP_CONN_LOCAL_BUSY 0x0040 +#define L2CAP_CONN_REJ_ACT 0x0080 +#define L2CAP_CONN_SEND_FBIT 0x0100 #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index a9c152a09f0..06687e26470 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1383,6 +1383,10 @@ static int l2cap_ertm_send(struct sock *sk) bt_cb(skb)->retries++; control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + 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) | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1404,6 +1408,7 @@ static int l2cap_ertm_send(struct sock *sk) pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; pi->unacked_frames++; + pi->frames_sent++; if (skb_queue_is_last(TX_QUEUE(sk), skb)) sk->sk_send_head = NULL; @@ -2191,6 +2196,7 @@ static inline void l2cap_ertm_init(struct sock *sk) l2cap_pi(sk)->unacked_frames = 0; l2cap_pi(sk)->buffer_seq = 0; l2cap_pi(sk)->num_to_ack = 0; + l2cap_pi(sk)->frames_sent = 0; setup_timer(&l2cap_pi(sk)->retrans_timer, l2cap_retrans_timeout, (unsigned long) sk); @@ -3148,6 +3154,38 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) return 0; } +static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + u16 control = 0; + + pi->frames_sent = 0; + pi->conn_state |= L2CAP_CONN_SEND_FBIT; + + 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; + l2cap_send_sframe(pi, control); + pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + } + + if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0) + __mod_retrans_timer(); + + l2cap_ertm_send(sk); + + if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) && + pi->frames_sent == 0) { + control |= L2CAP_SUPER_RCV_READY; + if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + control |= L2CAP_CTRL_FINAL; + pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + } + l2cap_send_sframe(pi, control); + } +} + static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) { struct sk_buff *next_skb; @@ -3418,10 +3456,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str switch (rx_control & L2CAP_CTRL_SUPERVISE) { case L2CAP_SUPER_RCV_READY: if (rx_control & L2CAP_CTRL_POLL) { - u16 control = L2CAP_CTRL_FINAL; - control |= L2CAP_SUPER_RCV_READY | - (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT); - l2cap_send_sframe(l2cap_pi(sk), control); + l2cap_send_i_or_rr_or_rnr(sk); pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; } else if (rx_control & L2CAP_CTRL_FINAL) { -- cgit v1.2.3-70-g09d2 From 1d8f5d16913d74e428950ee02fe9ff7e6391c120 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:37 -0300 Subject: Bluetooth: Support case with F bit set under WAIT_F state. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On receipt of a F=1 under WAIT_F state ERTM shall stop monitor timer and start retransmission timer (if there are unacked frames). 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, 14 insertions(+), 8 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 06687e26470..36cd4e4e6ad 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3364,6 +3364,13 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + if (L2CAP_CTRL_FINAL & rx_control) { + del_timer(&pi->monitor_timer); + if (pi->unacked_frames > 0) + __mod_retrans_timer(); + pi->conn_state &= ~L2CAP_CONN_WAIT_F; + } + pi->expected_ack_seq = req_seq; l2cap_drop_acked_frames(sk); @@ -3453,6 +3460,13 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + if (L2CAP_CTRL_FINAL & rx_control) { + del_timer(&pi->monitor_timer); + if (pi->unacked_frames > 0) + __mod_retrans_timer(); + pi->conn_state &= ~L2CAP_CONN_WAIT_F; + } + switch (rx_control & L2CAP_CTRL_SUPERVISE) { case L2CAP_SUPER_RCV_READY: if (rx_control & L2CAP_CTRL_POLL) { @@ -3472,14 +3486,6 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str l2cap_ertm_send(sk); } - if (!(pi->conn_state & L2CAP_CONN_WAIT_F)) - break; - - pi->conn_state &= ~L2CAP_CONN_WAIT_F; - del_timer(&pi->monitor_timer); - - if (pi->unacked_frames > 0) - __mod_retrans_timer(); } else { pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); -- cgit v1.2.3-70-g09d2 From 277ffbe362823d18a17792fbd8e507010e666299 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:37 -0300 Subject: Bluetooth: Check the minimum {I,S}-frame size into L2CAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All packets with size fewer than the minimum specified is dropped. Note that the size of the l2cap basic header, FCS and SAR fields are already subtracted of len at the moment of the size check. 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, 11 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 36cd4e4e6ad..ac00f5fac2d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3627,10 +3627,17 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (l2cap_check_fcs(pi, skb)) goto drop; - if (__is_iframe(control)) + if (__is_iframe(control)) { + if (len < 4) + goto drop; + l2cap_data_channel_iframe(sk, control, skb); - else + } else { + if (len != 0) + goto drop; + l2cap_data_channel_sframe(sk, control, skb); + } goto done; @@ -3645,7 +3652,8 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (pi->fcs == L2CAP_FCS_CRC16) len -= 2; - if (len > L2CAP_DEFAULT_MAX_PDU_SIZE || __is_sframe(control)) + if (len > L2CAP_DEFAULT_MAX_PDU_SIZE || len < 4 + || __is_sframe(control)) goto drop; if (l2cap_check_fcs(pi, skb)) -- cgit v1.2.3-70-g09d2 From 36f2fd585f43199f006a3b5ff84e95815102cd31 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:37 -0300 Subject: Bluetooth: Check if SDU size is greater than MTU on L2CAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After reassembly the SDU we need to check his size. It can't overflow the MTU size. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita 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 ac00f5fac2d..2e354d29f10 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3277,15 +3277,19 @@ static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 co pi->conn_state &= ~L2CAP_CONN_SAR_SDU; pi->partial_sdu_len += skb->len; + if (pi->partial_sdu_len > pi->imtu) + goto drop; + if (pi->partial_sdu_len == pi->sdu_len) { _skb = skb_clone(pi->sdu, GFP_ATOMIC); err = sock_queue_rcv_skb(sk, _skb); if (err < 0) kfree_skb(_skb); } - kfree_skb(pi->sdu); err = 0; +drop: + kfree_skb(pi->sdu); break; } -- cgit v1.2.3-70-g09d2 From 9e917af13d59182f95bbb5483dc0c4254dfb7944 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:37 -0300 Subject: Bluetooth: Implement SendAck() Action on ERTM. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shall be used to ack received frames, It must decide type of acknowledgment between a RR frame, a RNR frame or transmission of pending I-frames. It also modifies l2cap_ertm_send() to report the number of frames sent. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 2e354d29f10..0a739ef167c 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -352,6 +352,11 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) count = min_t(unsigned int, conn->mtu, hlen); control |= L2CAP_CTRL_FRAME_TYPE; + if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + control |= L2CAP_CTRL_FINAL; + pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + } + skb = bt_skb_alloc(count, GFP_ATOMIC); if (!skb) return -ENOMEM; @@ -1364,7 +1369,7 @@ static int l2cap_ertm_send(struct sock *sk) struct sk_buff *skb, *tx_skb; struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; - int err; + int err, nsent = 0; if (pi->conn_state & L2CAP_CONN_WAIT_F) return 0; @@ -1414,8 +1419,27 @@ static int l2cap_ertm_send(struct sock *sk) sk->sk_send_head = NULL; else sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); + + nsent++; } + return nsent; +} + +static int l2cap_send_ack(struct l2cap_pinfo *pi) +{ + struct sock *sk = (struct sock *)pi; + u16 control = 0; + + control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + + if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + control |= L2CAP_SUPER_RCV_NOT_READY; + return l2cap_send_sframe(pi, control); + } else if (l2cap_ertm_send(sk) == 0) { + control |= L2CAP_SUPER_RCV_READY; + return l2cap_send_sframe(pi, control); + } return 0; } @@ -1678,7 +1702,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms else err = l2cap_ertm_send(sk); - if (!err) + if (err >= 0) err = len; break; @@ -3178,10 +3202,6 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) && pi->frames_sent == 0) { control |= L2CAP_SUPER_RCV_READY; - if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { - control |= L2CAP_CTRL_FINAL; - pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; - } l2cap_send_sframe(pi, control); } } @@ -3362,7 +3382,6 @@ 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; @@ -3449,11 +3468,9 @@ expected: return err; pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; - if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) { - tx_control |= L2CAP_SUPER_RCV_READY; - tx_control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; - l2cap_send_sframe(pi, tx_control); - } + if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) + l2cap_send_ack(pi); + return 0; } -- cgit v1.2.3-70-g09d2 From f0946ccfc7da403a46b7ff7cb2e3deffac108742 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:37 -0300 Subject: Bluetooth: Move set of P-bit to l2cap_send_sframe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Abstract the send of of P-bit and avoids code duplication like we did with the setting of F-bit. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 0a739ef167c..852c1400d06 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -357,6 +357,11 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; } + if (pi->conn_state & L2CAP_CONN_SEND_PBIT) { + control |= L2CAP_CTRL_POLL; + pi->conn_state &= ~L2CAP_CONN_SEND_PBIT; + } + skb = bt_skb_alloc(count, GFP_ATOMIC); if (!skb) return -ENOMEM; @@ -3364,10 +3369,6 @@ static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) while (tx_seq != pi->expected_tx_seq) { control = L2CAP_SUPER_SELECT_REJECT; control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; - if (pi->conn_state & L2CAP_CONN_SEND_PBIT) { - control |= L2CAP_CTRL_POLL; - pi->conn_state &= ~L2CAP_CONN_SEND_PBIT; - } l2cap_send_sframe(pi, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); -- cgit v1.2.3-70-g09d2 From 73edaa9933219e25d6733b78d1e2c881025705e2 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:38 -0300 Subject: Bluetooth: Add Recv RR (P=0)(F=0) for SREJ_SENT state on ERTM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This finishes the implementation of Recv RR (P=0)(F=0) for the Enhanced Retransmission Mode on L2CAP. 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, 4 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 852c1400d06..e5cd64ac6fb 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3517,7 +3517,10 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str __mod_retrans_timer(); pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - l2cap_ertm_send(sk); + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) + l2cap_send_ack(pi); + else + l2cap_ertm_send(sk); } break; -- cgit v1.2.3-70-g09d2 From e072745f4adb01b909bd08a0cfc8f79348f4d2c6 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:38 -0300 Subject: Bluetooth: Split l2cap_data_channel_sframe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a function for each type fo S-frame and avoid a lot of nested code. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 204 ++++++++++++++++++++++++++++---------------------- 1 file changed, 115 insertions(+), 89 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index e5cd64ac6fb..068edf7704b 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3475,120 +3475,146 @@ expected: return 0; } -static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) +static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) { struct l2cap_pinfo *pi = l2cap_pi(sk); u8 tx_seq = __get_reqseq(rx_control); - BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); - - if (L2CAP_CTRL_FINAL & rx_control) { - del_timer(&pi->monitor_timer); - if (pi->unacked_frames > 0) - __mod_retrans_timer(); - pi->conn_state &= ~L2CAP_CONN_WAIT_F; - } + if (rx_control & L2CAP_CTRL_POLL) { + l2cap_send_i_or_rr_or_rnr(sk); + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - switch (rx_control & L2CAP_CTRL_SUPERVISE) { - case L2CAP_SUPER_RCV_READY: - if (rx_control & L2CAP_CTRL_POLL) { - l2cap_send_i_or_rr_or_rnr(sk); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - - } else if (rx_control & L2CAP_CTRL_FINAL) { - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - 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); - } + } else if (rx_control & L2CAP_CTRL_FINAL) { + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + pi->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(sk); - } else { - 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_REMOTE_BUSY) && - (pi->unacked_frames > 0)) - __mod_retrans_timer(); + } else { + pi->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(sk); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - if (pi->conn_state & L2CAP_CONN_SREJ_SENT) - l2cap_send_ack(pi); - else - l2cap_ertm_send(sk); - } - break; + if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && + (pi->unacked_frames > 0)) + __mod_retrans_timer(); - case L2CAP_SUPER_REJECT: pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) + l2cap_send_ack(pi); + else + l2cap_ertm_send(sk); + } +} - pi->expected_ack_seq = __get_reqseq(rx_control); - l2cap_drop_acked_frames(sk); +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); - 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 { + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + + pi->expected_ack_seq = __get_reqseq(rx_control); + l2cap_drop_acked_frames(sk); + + 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); - - if (pi->conn_state & L2CAP_CONN_WAIT_F) { - pi->srej_save_reqseq = tx_seq; - 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); - break; + if (pi->conn_state & L2CAP_CONN_WAIT_F) { + pi->srej_save_reqseq = tx_seq; + pi->conn_state |= L2CAP_CONN_REJ_ACT; + } + } +} +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); - case L2CAP_SUPER_SELECT_REJECT: - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - if (rx_control & L2CAP_CTRL_POLL) { - 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; - pi->conn_state |= L2CAP_CONN_SREJ_ACT; - } - } else if (rx_control & L2CAP_CTRL_FINAL) { - if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && - pi->srej_save_reqseq == tx_seq) - pi->conn_state &= ~L2CAP_CONN_SREJ_ACT; - else - l2cap_retransmit_frame(sk, tx_seq); + if (rx_control & L2CAP_CTRL_POLL) { + 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; + pi->conn_state |= L2CAP_CONN_SREJ_ACT; } - else { + } else if (rx_control & L2CAP_CTRL_FINAL) { + if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && + pi->srej_save_reqseq == tx_seq) + pi->conn_state &= ~L2CAP_CONN_SREJ_ACT; + else l2cap_retransmit_frame(sk, tx_seq); - if (pi->conn_state & L2CAP_CONN_WAIT_F) { - pi->srej_save_reqseq = tx_seq; - pi->conn_state |= L2CAP_CONN_SREJ_ACT; - } + } else { + l2cap_retransmit_frame(sk, tx_seq); + if (pi->conn_state & L2CAP_CONN_WAIT_F) { + pi->srej_save_reqseq = tx_seq; + pi->conn_state |= L2CAP_CONN_SREJ_ACT; } + } +} + +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); + + pi->conn_state |= L2CAP_CONN_REMOTE_BUSY; + pi->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(sk); + + del_timer(&pi->retrans_timer); + if (rx_control & L2CAP_CTRL_POLL) { + u16 control = L2CAP_CTRL_FINAL; + l2cap_send_rr_or_rnr(pi, control); + } +} + +static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) +{ + BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + + if (L2CAP_CTRL_FINAL & rx_control) { + del_timer(&l2cap_pi(sk)->monitor_timer); + if (l2cap_pi(sk)->unacked_frames > 0) + __mod_retrans_timer(); + l2cap_pi(sk)->conn_state &= ~L2CAP_CONN_WAIT_F; + } + + switch (rx_control & L2CAP_CTRL_SUPERVISE) { + case L2CAP_SUPER_RCV_READY: + l2cap_data_channel_rrframe(sk, rx_control); break; - case L2CAP_SUPER_RCV_NOT_READY: - pi->conn_state |= L2CAP_CONN_REMOTE_BUSY; - pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(sk); + case L2CAP_SUPER_REJECT: + l2cap_data_channel_rejframe(sk, rx_control); + break; - del_timer(&pi->retrans_timer); - if (rx_control & L2CAP_CTRL_POLL) { - u16 control = L2CAP_CTRL_FINAL; - l2cap_send_rr_or_rnr(pi, control); - } + case L2CAP_SUPER_SELECT_REJECT: + l2cap_data_channel_srejframe(sk, rx_control); + break; + + case L2CAP_SUPER_RCV_NOT_READY: + l2cap_data_channel_rnrframe(sk, rx_control); break; } -- cgit v1.2.3-70-g09d2 From 99b0d4b7b09edeacf4542bced5c01239375b51a9 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:38 -0300 Subject: Bluetooth: Handle all cases of receipt of RNR-frames into L2CAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We weren't handling the receipt under SREJ_SENT state table. It also introduce l2cap_send_srejtail(). It will be used in the nexts commits too. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 068edf7704b..8937a842347 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1448,6 +1448,22 @@ static int l2cap_send_ack(struct l2cap_pinfo *pi) return 0; } +static int l2cap_send_srejtail(struct sock *sk) +{ + struct srej_list *tail; + u16 control; + + control = L2CAP_SUPER_SELECT_REJECT; + control |= L2CAP_CTRL_FINAL; + + tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list); + control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + + l2cap_send_sframe(l2cap_pi(sk), control); + + return 0; +} + static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; @@ -3582,11 +3598,19 @@ static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control) pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); - del_timer(&pi->retrans_timer); - if (rx_control & L2CAP_CTRL_POLL) { - u16 control = L2CAP_CTRL_FINAL; - l2cap_send_rr_or_rnr(pi, control); + if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) { + del_timer(&pi->retrans_timer); + if (rx_control & L2CAP_CTRL_POLL) { + u16 control = L2CAP_CTRL_FINAL; + l2cap_send_rr_or_rnr(pi, control); + } + return; } + + if (rx_control & L2CAP_CTRL_POLL) + l2cap_send_srejtail(sk); + else + l2cap_send_sframe(pi, L2CAP_SUPER_RCV_READY); } static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) -- cgit v1.2.3-70-g09d2 From 6e3a59819fac19006fe4255b87928e5a12c54532 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:38 -0300 Subject: Bluetooth: Group the ack of I-frames into l2cap_data_channel_rrframe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It also fix a bug: we weren't acknowledging I-frames when P=1. Note that when F=1 we are acknowledging packets before setting RemoteBusy to False. The spec says we should do that in the opposite order, but acknowledment of packets doesn't care about RemoteBusy flag so we can do that in the order we want. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 8937a842347..d096c7c11ab 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3494,7 +3494,9 @@ expected: static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) { struct l2cap_pinfo *pi = l2cap_pi(sk); - u8 tx_seq = __get_reqseq(rx_control); + + pi->expected_ack_seq = __get_reqseq(rx_control); + l2cap_drop_acked_frames(sk); if (rx_control & L2CAP_CTRL_POLL) { l2cap_send_i_or_rr_or_rnr(sk); @@ -3502,8 +3504,6 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) } else if (rx_control & L2CAP_CTRL_FINAL) { pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - 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; @@ -3514,9 +3514,6 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) } } else { - pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(sk); - if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && (pi->unacked_frames > 0)) __mod_retrans_timer(); -- cgit v1.2.3-70-g09d2 From 8abb52ee00c4b3f857269eb6b7145991bab869bf Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:38 -0300 Subject: Bluetooth: Remove duplicate use of __get_reqseq() macro on L2CAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tx_seq var already has the value of __get_reqseq(). Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita 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 d096c7c11ab..e9ac9fb1191 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3533,7 +3533,7 @@ static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control) pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - pi->expected_ack_seq = __get_reqseq(rx_control); + pi->expected_ack_seq = tx_seq; l2cap_drop_acked_frames(sk); if (rx_control & L2CAP_CTRL_FINAL) { -- cgit v1.2.3-70-g09d2 From 05fbd89dd4153341717b33d9e8ae8bd29db6c1c8 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:39 -0300 Subject: Bluetooth: Finish implementation for Rec RR (P=1) on ERTM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now the code handles the case under SREJ_SENT state. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index e9ac9fb1191..f3869857ee9 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3499,8 +3499,17 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) l2cap_drop_acked_frames(sk); if (rx_control & L2CAP_CTRL_POLL) { - l2cap_send_i_or_rr_or_rnr(sk); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && + (pi->unacked_frames > 0)) + __mod_retrans_timer(); + + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + l2cap_send_srejtail(sk); + } else { + l2cap_send_i_or_rr_or_rnr(sk); + pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + } } else if (rx_control & L2CAP_CTRL_FINAL) { pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; -- cgit v1.2.3-70-g09d2 From c1b4f43be01c2a363be021485dd18cca33cfab8a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:39 -0300 Subject: Bluetooth: Add timer to Acknowledge I-frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We ack I-frames on each txWindow/5 I-frames received, but if the sender stop to send I-frames and it's not a txWindow multiple we can leave some frames unacked. So I added a timer to ack I-frames on this case. The timer expires in 200ms. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 4 ++++ net/bluetooth/l2cap.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d9c20c3d6f3..48f10f46c73 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -35,6 +35,7 @@ #define L2CAP_DEFAULT_RETRANS_TO 1000 /* 1 second */ #define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ #define L2CAP_DEFAULT_MAX_PDU_SIZE 672 +#define L2CAP_DEFAULT_ACK_TO 200 #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ #define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ @@ -348,6 +349,7 @@ struct l2cap_pinfo { struct timer_list retrans_timer; struct timer_list monitor_timer; + struct timer_list ack_timer; struct sk_buff_head tx_queue; struct sk_buff_head srej_queue; struct srej_list srej_l; @@ -382,6 +384,8 @@ struct l2cap_pinfo { jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); #define __mod_monitor_timer() mod_timer(&l2cap_pi(sk)->monitor_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO)); +#define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \ + jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); static inline int l2cap_tx_window_full(struct sock *sk) { diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index f3869857ee9..03006568f8a 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2235,6 +2235,15 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) *ptr += L2CAP_CONF_OPT_SIZE + len; } +static void l2cap_ack_timeout(unsigned long arg) +{ + struct sock *sk = (void *) arg; + + bh_lock_sock(sk); + l2cap_send_ack(l2cap_pi(sk)); + bh_unlock_sock(sk); +} + static inline void l2cap_ertm_init(struct sock *sk) { l2cap_pi(sk)->expected_ack_seq = 0; @@ -2247,6 +2256,8 @@ static inline void l2cap_ertm_init(struct sock *sk) l2cap_retrans_timeout, (unsigned long) sk); setup_timer(&l2cap_pi(sk)->monitor_timer, l2cap_monitor_timeout, (unsigned long) sk); + setup_timer(&l2cap_pi(sk)->ack_timer, + l2cap_ack_timeout, (unsigned long) sk); __skb_queue_head_init(SREJ_QUEUE(sk)); } @@ -2975,6 +2986,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd skb_queue_purge(SREJ_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); @@ -3005,6 +3017,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd skb_queue_purge(SREJ_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); @@ -3484,6 +3497,8 @@ expected: if (err < 0) return err; + __mod_ack_timer(); + pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) l2cap_send_ack(pi); -- cgit v1.2.3-70-g09d2 From 2fb862e215e53630066c677e06d7551fa38bf235 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:39 -0300 Subject: Bluetooth: Ignore Tx Window value with Streaming mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tx Window value shall not be used with Streaming Mode and the receiver of the config Request shall ignore its value. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 03006568f8a..f604405fe66 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2495,7 +2495,6 @@ done: break; case L2CAP_MODE_STREAMING: - pi->remote_tx_win = rfc.txwin_size; pi->max_pdu_size = rfc.max_pdu_size; pi->conf_state |= L2CAP_CONF_MODE_DONE; -- cgit v1.2.3-70-g09d2 From 7b1c0049be3aabc18831ada339dbcf41ba8c81fd Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:39 -0300 Subject: Bluetooth: Read RFC conf option on a successful Conf RSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Enhanced Retransmission Mode and Streaming Mode a entity can send, on a successful Conf RSP, new values for the RFC fields. For example, the entity can send txWindow and MPS values less than the value received on a Conf REQ. 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, 38 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index f604405fe66..c50c05738fb 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2602,6 +2602,42 @@ static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 fla return ptr - data; } +static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + int type, olen; + unsigned long val; + struct l2cap_conf_rfc rfc; + + BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len); + + if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING)) + return; + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); + + switch (type) { + case L2CAP_CONF_RFC: + if (olen == sizeof(rfc)) + memcpy(&rfc, (void *)val, olen); + goto done; + } + } + +done: + switch (rfc.mode) { + case L2CAP_MODE_ERTM: + pi->remote_tx_win = rfc.txwin_size; + pi->retrans_timeout = rfc.retrans_timeout; + pi->monitor_timeout = rfc.monitor_timeout; + pi->mps = le16_to_cpu(rfc.max_pdu_size); + break; + case L2CAP_MODE_STREAMING: + pi->mps = le16_to_cpu(rfc.max_pdu_size); + } +} + static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) { struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data; @@ -2881,6 +2917,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; u16 scid, flags, result; struct sock *sk; + int len = cmd->len - sizeof(*rsp); scid = __le16_to_cpu(rsp->scid); flags = __le16_to_cpu(rsp->flags); @@ -2895,11 +2932,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr switch (result) { case L2CAP_CONF_SUCCESS: + l2cap_conf_rfc_get(sk, rsp->data, len); break; case L2CAP_CONF_UNACCEPT: if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { - int len = cmd->len - sizeof(*rsp); char req[64]; if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { -- cgit v1.2.3-70-g09d2 From 1c7621596d11b9c3e19eb88a818758dee4901c95 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:40 -0300 Subject: Bluetooth: Fix configuration of the MPS value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were accepting values bigger than we can accept. This was leading ERTM to drop packets because of wrong FCS checks. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 3 ++- net/bluetooth/l2cap.c | 36 ++++++++++++++++++++---------------- 2 files changed, 22 insertions(+), 17 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 48f10f46c73..0f4e4234c5f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -343,7 +343,8 @@ struct l2cap_pinfo { __u8 remote_max_tx; __u16 retrans_timeout; __u16 monitor_timeout; - __u16 max_pdu_size; + __u16 remote_mps; + __u16 mps; __le16 sport; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c50c05738fb..94be5dbb256 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1606,21 +1606,21 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz __skb_queue_head_init(&sar_queue); control = L2CAP_SDU_START; - skb = l2cap_create_iframe_pdu(sk, msg, pi->max_pdu_size, control, len); + skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len); if (IS_ERR(skb)) return PTR_ERR(skb); __skb_queue_tail(&sar_queue, skb); - len -= pi->max_pdu_size; - size +=pi->max_pdu_size; + len -= pi->remote_mps; + size += pi->remote_mps; control = 0; while (len > 0) { size_t buflen; - if (len > pi->max_pdu_size) { + if (len > pi->remote_mps) { control |= L2CAP_SDU_CONTINUE; - buflen = pi->max_pdu_size; + buflen = pi->remote_mps; } else { control |= L2CAP_SDU_END; buflen = len; @@ -1701,7 +1701,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: /* Entire SDU fits into one PDU */ - if (len <= pi->max_pdu_size) { + if (len <= pi->remote_mps) { control = L2CAP_SDU_UNSEGMENTED; skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0); if (IS_ERR(skb)) { @@ -2330,7 +2330,7 @@ done: rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) - rfc.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); @@ -2353,7 +2353,7 @@ done: rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) - rfc.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); @@ -2482,7 +2482,10 @@ done: case L2CAP_MODE_ERTM: pi->remote_tx_win = rfc.txwin_size; pi->remote_max_tx = rfc.max_transmit; - pi->max_pdu_size = rfc.max_pdu_size; + if (rfc.max_pdu_size > pi->conn->mtu - 10) + rfc.max_pdu_size = le16_to_cpu(pi->conn->mtu - 10); + + pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); rfc.retrans_timeout = L2CAP_DEFAULT_RETRANS_TO; rfc.monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; @@ -2495,7 +2498,10 @@ done: break; case L2CAP_MODE_STREAMING: - pi->max_pdu_size = rfc.max_pdu_size; + if (rfc.max_pdu_size > pi->conn->mtu - 10) + rfc.max_pdu_size = le16_to_cpu(pi->conn->mtu - 10); + + pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); pi->conf_state |= L2CAP_CONF_MODE_DONE; @@ -2574,11 +2580,10 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, pi->remote_tx_win = rfc.txwin_size; pi->retrans_timeout = rfc.retrans_timeout; pi->monitor_timeout = rfc.monitor_timeout; - pi->max_pdu_size = le16_to_cpu(rfc.max_pdu_size); + pi->mps = le16_to_cpu(rfc.max_pdu_size); break; case L2CAP_MODE_STREAMING: - pi->max_pdu_size = le16_to_cpu(rfc.max_pdu_size); - break; + pi->mps = le16_to_cpu(rfc.max_pdu_size); } } @@ -3753,7 +3758,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk * Receiver will miss it and start proper recovery * procedures and ask retransmission. */ - if (len > L2CAP_DEFAULT_MAX_PDU_SIZE) + if (len > pi->mps) goto drop; if (l2cap_check_fcs(pi, skb)) @@ -3784,8 +3789,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 > L2CAP_DEFAULT_MAX_PDU_SIZE || len < 4 - || __is_sframe(control)) + if (len > pi->mps || len < 4 || __is_sframe(control)) goto drop; if (l2cap_check_fcs(pi, skb)) -- cgit v1.2.3-70-g09d2 From 10467e9e9b89272b25b56688bb276d0830e9ab9a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:40 -0300 Subject: Bluetooth: Add le16 macro to Retransmission and Monitor Timeouts values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a possible problem with Big Endian machines. 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, 8 insertions(+), 6 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 94be5dbb256..0889949b689 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2487,8 +2487,10 @@ done: pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); - rfc.retrans_timeout = L2CAP_DEFAULT_RETRANS_TO; - rfc.monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; + rfc.retrans_timeout = + le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = + le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO); pi->conf_state |= L2CAP_CONF_MODE_DONE; @@ -2578,8 +2580,8 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, switch (rfc.mode) { case L2CAP_MODE_ERTM: pi->remote_tx_win = rfc.txwin_size; - pi->retrans_timeout = rfc.retrans_timeout; - pi->monitor_timeout = rfc.monitor_timeout; + pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); + pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); pi->mps = le16_to_cpu(rfc.max_pdu_size); break; case L2CAP_MODE_STREAMING: @@ -2634,8 +2636,8 @@ done: switch (rfc.mode) { case L2CAP_MODE_ERTM: pi->remote_tx_win = rfc.txwin_size; - pi->retrans_timeout = rfc.retrans_timeout; - pi->monitor_timeout = rfc.monitor_timeout; + pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); + pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); pi->mps = le16_to_cpu(rfc.max_pdu_size); break; case L2CAP_MODE_STREAMING: -- cgit v1.2.3-70-g09d2 From 052897ca5019d9157ae09e5e84eee2a9ef5dccc6 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:40 -0300 Subject: Bluetooth: Check the SDU size against the MTU value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the SDU size is greater than the MTU something is wrong, so report an error. Signed-off-by: Gustavo F. Padovan [jprvita@profusion.mobi: set err to appropriate errno value] Signed-off-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 0889949b689..e936913c921 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3338,6 +3338,11 @@ static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 co pi->sdu_len = get_unaligned_le16(skb->data); skb_pull(skb, 2); + if (pi->sdu_len > pi->imtu) { + err = -EMSGSIZE; + break; + } + pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); if (!pi->sdu) { err = -ENOMEM; -- cgit v1.2.3-70-g09d2 From 855666cccc939d392316de17512e17a08b2fa05a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:40 -0300 Subject: Bluetooth: Send Ack after clear the SREJ list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As specified by Bluetooth 3.0 spec we shall send an acknowledgment using the Send-Ack() after clear the SREJ list. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita 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 e936913c921..c6bc1b9ed65 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3493,6 +3493,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str if (list_empty(SREJ_LIST(sk))) { pi->buffer_seq = pi->buffer_seq_srej; pi->conn_state &= ~L2CAP_CONN_SREJ_SENT; + l2cap_send_ack(pi); } } else { struct srej_list *l; -- cgit v1.2.3-70-g09d2 From 14b5aa71ec506f4e38ca6a1dc02ecd668ecfd902 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:40 -0300 Subject: Bluetooth: Add sockopt configuration for txWindow on L2CAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now we can set/get Transmission Window size via sockopt. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 2 ++ net/bluetooth/l2cap.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 0f4e4234c5f..07ae4ccfffb 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -56,6 +56,7 @@ struct l2cap_options { __u16 flush_to; __u8 mode; __u8 fcs; + __u16 txwin_size; }; #define L2CAP_CONNINFO 0x02 @@ -339,6 +340,7 @@ struct l2cap_pinfo { __u8 ident; + __u8 tx_win; __u8 remote_tx_win; __u8 remote_max_tx; __u16 retrans_timeout; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index c6bc1b9ed65..530079649b4 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -782,6 +782,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->omtu = l2cap_pi(parent)->omtu; pi->mode = l2cap_pi(parent)->mode; pi->fcs = l2cap_pi(parent)->fcs; + pi->tx_win = l2cap_pi(parent)->tx_win; pi->sec_level = l2cap_pi(parent)->sec_level; pi->role_switch = l2cap_pi(parent)->role_switch; pi->force_reliable = l2cap_pi(parent)->force_reliable; @@ -790,6 +791,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->omtu = 0; pi->mode = L2CAP_MODE_BASIC; pi->fcs = L2CAP_FCS_CRC16; + pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; pi->sec_level = BT_SECURITY_LOW; pi->role_switch = 0; pi->force_reliable = 0; @@ -1782,6 +1784,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; opts.fcs = l2cap_pi(sk)->fcs; + opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; len = min_t(unsigned int, sizeof(opts), optlen); if (copy_from_user((char *) &opts, optval, len)) { @@ -1793,6 +1796,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us l2cap_pi(sk)->omtu = opts.omtu; l2cap_pi(sk)->mode = opts.mode; l2cap_pi(sk)->fcs = opts.fcs; + l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size; break; case L2CAP_LM: @@ -1907,6 +1911,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; opts.fcs = l2cap_pi(sk)->fcs; + opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; len = min_t(unsigned int, len, sizeof(opts)); if (copy_to_user(optval, (char *) &opts, len)) @@ -2324,7 +2329,7 @@ done: case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; - rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; + rfc.txwin_size = pi->tx_win; rfc.max_transmit = max_transmit; rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; -- cgit v1.2.3-70-g09d2 From 803020c6fa63aa738cfda3329c9675b42023e9d2 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:41 -0300 Subject: Bluetooth: Change acknowledgement to use the value of txWindow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we can set the txWindow we need to change the acknowledgement procedure to ack after each (pi->txWindow/6 + 1). The plus 1 is to avoid the zero value. It also renames pi->num_to_ack to a better name: pi->num_acked. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 3 +-- net/bluetooth/l2cap.c | 7 ++++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 07ae4ccfffb..059260bed4e 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -30,7 +30,6 @@ #define L2CAP_DEFAULT_MIN_MTU 48 #define L2CAP_DEFAULT_FLUSH_TO 0xffff #define L2CAP_DEFAULT_TX_WINDOW 63 -#define L2CAP_DEFAULT_NUM_TO_ACK (L2CAP_DEFAULT_TX_WINDOW/5) #define L2CAP_DEFAULT_MAX_TX 3 #define L2CAP_DEFAULT_RETRANS_TO 1000 /* 1 second */ #define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ @@ -333,7 +332,7 @@ struct l2cap_pinfo { __u8 frames_sent; __u8 unacked_frames; __u8 retry_count; - __u8 num_to_ack; + __u8 num_acked; __u16 sdu_len; __u16 partial_sdu_len; struct sk_buff *sdu; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 530079649b4..0b0b237bb78 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2254,7 +2254,7 @@ static inline void l2cap_ertm_init(struct sock *sk) l2cap_pi(sk)->expected_ack_seq = 0; l2cap_pi(sk)->unacked_frames = 0; l2cap_pi(sk)->buffer_seq = 0; - l2cap_pi(sk)->num_to_ack = 0; + l2cap_pi(sk)->num_acked = 0; l2cap_pi(sk)->frames_sent = 0; setup_timer(&l2cap_pi(sk)->retrans_timer, @@ -3466,6 +3466,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; + 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); @@ -3553,8 +3554,8 @@ expected: __mod_ack_timer(); - pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK; - if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) + pi->num_acked = (pi->num_acked + 1) % num_to_ack; + if (pi->num_acked == num_to_ack - 1) l2cap_send_ack(pi); return 0; -- cgit v1.2.3-70-g09d2 From 369ba30264826f38eefc61b93688100be8adbd4d Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:41 -0300 Subject: Bluetooth: Add module parameter for txWindow size on L2CAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Very useful for testing purposes. Signed-off-by: Gustavo F. Padovan [jprvita@profusion.mobi: improved parameter description] Signed-off-by: João Paulo Rechi Vita 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 0b0b237bb78..ff1466b2158 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -57,6 +57,7 @@ static int enable_ertm = 0; 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, }; @@ -791,7 +792,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->omtu = 0; pi->mode = L2CAP_MODE_BASIC; pi->fcs = L2CAP_FCS_CRC16; - pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; + pi->tx_win = tx_window; pi->sec_level = BT_SECURITY_LOW; pi->role_switch = 0; pi->force_reliable = 0; @@ -4296,6 +4297,9 @@ 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-70-g09d2 From 68d7f0ce911e41e463c45911be031cdf6a096fe8 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:41 -0300 Subject: Bluetooth: Enable option to configure Max Transmission value via sockopt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the sockopt extension we can set a per-channel MaxTx value. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 2 ++ net/bluetooth/l2cap.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 059260bed4e..8942c2ffc58 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -55,6 +55,7 @@ struct l2cap_options { __u16 flush_to; __u8 mode; __u8 fcs; + __u8 max_tx; __u16 txwin_size; }; @@ -340,6 +341,7 @@ struct l2cap_pinfo { __u8 ident; __u8 tx_win; + __u8 max_tx; __u8 remote_tx_win; __u8 remote_max_tx; __u16 retrans_timeout; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index ff1466b2158..f9e4da2677a 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -783,6 +783,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->omtu = l2cap_pi(parent)->omtu; pi->mode = l2cap_pi(parent)->mode; pi->fcs = l2cap_pi(parent)->fcs; + pi->max_tx = l2cap_pi(parent)->max_tx; pi->tx_win = l2cap_pi(parent)->tx_win; pi->sec_level = l2cap_pi(parent)->sec_level; pi->role_switch = l2cap_pi(parent)->role_switch; @@ -791,6 +792,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->imtu = L2CAP_DEFAULT_MTU; pi->omtu = 0; pi->mode = L2CAP_MODE_BASIC; + pi->max_tx = max_transmit; pi->fcs = L2CAP_FCS_CRC16; pi->tx_win = tx_window; pi->sec_level = BT_SECURITY_LOW; @@ -1785,6 +1787,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; opts.fcs = l2cap_pi(sk)->fcs; + opts.max_tx = l2cap_pi(sk)->max_tx; opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; len = min_t(unsigned int, sizeof(opts), optlen); @@ -1797,6 +1800,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us l2cap_pi(sk)->omtu = opts.omtu; l2cap_pi(sk)->mode = opts.mode; l2cap_pi(sk)->fcs = opts.fcs; + l2cap_pi(sk)->max_tx = opts.max_tx; l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size; break; @@ -1912,6 +1916,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; opts.fcs = l2cap_pi(sk)->fcs; + opts.max_tx = l2cap_pi(sk)->max_tx; opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; len = min_t(unsigned int, len, sizeof(opts)); @@ -2331,7 +2336,7 @@ done: case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; rfc.txwin_size = pi->tx_win; - rfc.max_transmit = max_transmit; + rfc.max_transmit = pi->max_tx; rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); -- cgit v1.2.3-70-g09d2 From f6e6b16823de0aff31cb8ee8c098383e3aceec58 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:41 -0300 Subject: Bluetooth: Fix bug when retransmitting I-frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there is no frames to retransmit l2cap was crashing the kernel, now we check if the queue is empty first. 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, 8 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index f9e4da2677a..4c7b2d22faa 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3546,7 +3546,8 @@ expected: if (pi->conn_state & L2CAP_CONN_REJ_ACT) pi->conn_state &= ~L2CAP_CONN_REJ_ACT; else { - sk->sk_send_head = TX_QUEUE(sk)->next; + if (!skb_queue_empty(TX_QUEUE(sk))) + sk->sk_send_head = TX_QUEUE(sk)->next; pi->next_tx_seq = pi->expected_ack_seq; l2cap_ertm_send(sk); } @@ -3593,7 +3594,8 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) if (pi->conn_state & L2CAP_CONN_REJ_ACT) pi->conn_state &= ~L2CAP_CONN_REJ_ACT; else { - sk->sk_send_head = TX_QUEUE(sk)->next; + if (!skb_queue_empty(TX_QUEUE(sk))) + sk->sk_send_head = TX_QUEUE(sk)->next; pi->next_tx_seq = pi->expected_ack_seq; l2cap_ertm_send(sk); } @@ -3625,12 +3627,14 @@ static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control) if (pi->conn_state & L2CAP_CONN_REJ_ACT) pi->conn_state &= ~L2CAP_CONN_REJ_ACT; else { - sk->sk_send_head = TX_QUEUE(sk)->next; + if (!skb_queue_empty(TX_QUEUE(sk))) + 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; + if (!skb_queue_empty(TX_QUEUE(sk))) + sk->sk_send_head = TX_QUEUE(sk)->next; pi->next_tx_seq = pi->expected_ack_seq; l2cap_ertm_send(sk); -- cgit v1.2.3-70-g09d2 From 0ee0d20855ae9271de3f6695f4cafc08ab2533bb Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:41 -0300 Subject: Bluetooth: Fix crash when monitor timeout expires MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code was crashing due to a invalid access to hci_conn after the channel disconnect. 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, 3 insertions(+) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 4c7b2d22faa..2f9bbad4288 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1568,6 +1568,9 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *m BT_DBG("sk %p len %d", sk, (int)len); + if (!conn) + return ERR_PTR(-ENOTCONN); + if (sdulen) hlen += 2; -- cgit v1.2.3-70-g09d2 From 812e737e29a1d559e7bfbea675fdcfcbad9f5e1f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:42 -0300 Subject: Bluetooth: Fix drop of acked packets on ERTM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit l2cap_drop_acked_frames() was droping not sent packets, causing them to be not transmitted. 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, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 2f9bbad4288..042fd967e79 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1262,7 +1262,8 @@ static void l2cap_drop_acked_frames(struct sock *sk) { struct sk_buff *skb; - while ((skb = skb_peek(TX_QUEUE(sk)))) { + while ((skb = skb_peek(TX_QUEUE(sk))) && + l2cap_pi(sk)->unacked_frames) { if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq) break; -- cgit v1.2.3-70-g09d2 From 3b1a9f3fa6ad842991538da2c3b2e29e047b131f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:42 -0300 Subject: Bluetooth: Optimize SREJ_QUEUE append MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the I-frame received is the expected, i.e., its tx_seq is equal to expected_tx_seq and we are under a SREJ, we can just add it to the tail of the list. Doing that we change the complexity from O(n) to O(1). 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, 3 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 042fd967e79..187f46dd830 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3542,7 +3542,9 @@ expected: pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { - l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + bt_cb(skb)->tx_seq = tx_seq; + bt_cb(skb)->sar = sar; + __skb_queue_tail(SREJ_QUEUE(sk), skb); return 0; } -- cgit v1.2.3-70-g09d2 From 84fb0a6334af0ccad3544f6972c055d90fbb9fbe Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:42 -0300 Subject: Bluetooth: Add Kconfig option for L2CAP Extended Features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The L2CAP Extended Features are still unstable and under development, so we are adding them under the EXPERIMENTAL flag to get more feedback on them. L2CAP Extended Features includes the Enhanced Retransmission and Streaming Modes, Frame Check Sequence (FCS), and Segmentation and Reassemby (SAR). Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/Kconfig | 13 +++++++++++++ net/bluetooth/l2cap.c | 4 ++++ 2 files changed, 17 insertions(+) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index ed371684c13..ee3b3049d38 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -43,6 +43,19 @@ 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 187f46dd830..4c007203d66 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -55,7 +55,11 @@ #define VERSION "2.14" +#ifdef CONFIG_BT_L2CAP_EXT_FEATURES +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; -- cgit v1.2.3-70-g09d2 From bd3c9e255e76ae232d417e3914ca5d80ca3e9485 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:42 -0300 Subject: Bluetooth: Add SOCK_STREAM support to L2CAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit if enable_ertm is true and we have SOCK_STREAM the default mode will be ERTM, otherwise Basic Mode. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 4c007203d66..1a32562adf4 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -224,7 +224,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so l2cap_pi(sk)->conn = conn; - if (sk->sk_type == SOCK_SEQPACKET) { + if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) { /* Alloc CID for connection-oriented socket */ l2cap_pi(sk)->scid = l2cap_alloc_cid(l); } else if (sk->sk_type == SOCK_DGRAM) { @@ -452,7 +452,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { bh_lock_sock(sk); - if (sk->sk_type != SOCK_SEQPACKET) { + if (sk->sk_type != SOCK_SEQPACKET && + sk->sk_type != SOCK_STREAM) { bh_unlock_sock(sk); continue; } @@ -512,7 +513,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { bh_lock_sock(sk); - if (sk->sk_type != SOCK_SEQPACKET) { + if (sk->sk_type != SOCK_SEQPACKET && + sk->sk_type != SOCK_STREAM) { l2cap_sock_clear_timer(sk); sk->sk_state = BT_CONNECTED; sk->sk_state_change(sk); @@ -721,7 +723,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason) case BT_CONNECTED: case BT_CONFIG: - if (sk->sk_type == SOCK_SEQPACKET) { + if (sk->sk_type == SOCK_SEQPACKET || + sk->sk_type == SOCK_STREAM) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; sk->sk_state = BT_DISCONN; @@ -732,7 +735,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason) break; case BT_CONNECT2: - if (sk->sk_type == SOCK_SEQPACKET) { + if (sk->sk_type == SOCK_SEQPACKET || + sk->sk_type == SOCK_STREAM) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct l2cap_conn_rsp rsp; __u16 result; @@ -795,7 +799,10 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) } else { pi->imtu = L2CAP_DEFAULT_MTU; pi->omtu = 0; - pi->mode = L2CAP_MODE_BASIC; + if (enable_ertm && sk->sk_type == SOCK_STREAM) + pi->mode = L2CAP_MODE_ERTM; + else + pi->mode = L2CAP_MODE_BASIC; pi->max_tx = max_transmit; pi->fcs = L2CAP_FCS_CRC16; pi->tx_win = tx_window; @@ -852,7 +859,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, sock->state = SS_UNCONNECTED; - if (sock->type != SOCK_SEQPACKET && + if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; @@ -1000,7 +1007,8 @@ static int l2cap_do_connect(struct sock *sk) l2cap_sock_set_timer(sk, sk->sk_sndtimeo); if (hcon->state == BT_CONNECTED) { - if (sk->sk_type != SOCK_SEQPACKET) { + if (sk->sk_type != SOCK_SEQPACKET && + sk->sk_type != SOCK_STREAM) { l2cap_sock_clear_timer(sk); sk->sk_state = BT_CONNECTED; } else @@ -1034,7 +1042,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al lock_sock(sk); - if (sk->sk_type == SOCK_SEQPACKET && !la.l2_psm) { + if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) + && !la.l2_psm) { err = -EINVAL; goto done; } @@ -1098,7 +1107,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) lock_sock(sk); - if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) { + if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) + || sk->sk_state != BT_BOUND) { err = -EBADFD; goto done; } @@ -1857,7 +1867,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch switch (optname) { case BT_SECURITY: - if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) { + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM + && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } @@ -2007,7 +2018,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch switch (optname) { case BT_SECURITY: - if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) { + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM + && sk->sk_type != SOCK_RAW) { err = -EINVAL; break; } @@ -2314,7 +2326,7 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) { struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; - struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; + struct l2cap_conf_rfc rfc = { .mode = pi->mode }; void *ptr = req->data; BT_DBG("sk %p", sk); @@ -3997,7 +4009,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt) { - if (sk->sk_type != SOCK_SEQPACKET) + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) return; if (encrypt == 0x00) { -- cgit v1.2.3-70-g09d2 From 0041ecfa3025d7612fdaab12b2f07c9c3c09f42f Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Sat, 1 May 2010 16:15:42 -0300 Subject: Bluetooth: Check if mode is supported on getsockopt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add this check to getsockopt makes possible to fail early instead of waiting until listen / connect. Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 1a32562adf4..bf5bb7dc6ab 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1814,9 +1814,22 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } + l2cap_pi(sk)->mode = opts.mode; + switch (l2cap_pi(sk)->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: + case L2CAP_MODE_STREAMING: + if (enable_ertm) + break; + /* fall through */ + default: + err = -EINVAL; + break; + } + l2cap_pi(sk)->imtu = opts.imtu; l2cap_pi(sk)->omtu = opts.omtu; - l2cap_pi(sk)->mode = opts.mode; l2cap_pi(sk)->fcs = opts.fcs; l2cap_pi(sk)->max_tx = opts.max_tx; l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size; -- cgit v1.2.3-70-g09d2 From afefdbc4cf3b9d409d07e1e5264e7ff88bc48711 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:43 -0300 Subject: Bluetooth: Fix SDU reassembly under SREJ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code was reusing the control var without its reinitialization. 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 bf5bb7dc6ab..478def700c7 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3446,14 +3446,14 @@ drop: static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) { struct sk_buff *skb; - u16 control = 0; + u16 control; while((skb = skb_peek(SREJ_QUEUE(sk)))) { if (bt_cb(skb)->tx_seq != tx_seq) break; skb = skb_dequeue(SREJ_QUEUE(sk)); - control |= bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; + control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; l2cap_sar_reassembly_sdu(sk, skb, control); l2cap_pi(sk)->buffer_seq_srej = (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; -- cgit v1.2.3-70-g09d2 From 01760bdde9a92413b7fff928d08e19352bf09d82 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Sat, 1 May 2010 16:15:43 -0300 Subject: Bluetooth: Close L2CAP channel on invalid ReqSeq 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 | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 478def700c7..31514d8faa6 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3772,7 +3772,7 @@ 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; + u8 tx_seq, req_seq, next_tx_seq_offset, req_seq_offset; sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); if (!sk) { @@ -3823,6 +3823,22 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk 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) + 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); + goto drop; + } + if (__is_iframe(control)) { if (len < 4) goto drop; -- cgit v1.2.3-70-g09d2 From 44651b85cc3a076147af5d181fc4833ef8debc59 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:43 -0300 Subject: Bluetooth: Don't set control bits to zero first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can set the SAR bits in the control field directly. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 31514d8faa6..cfb18cd9756 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1636,16 +1636,15 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz __skb_queue_tail(&sar_queue, skb); len -= pi->remote_mps; size += pi->remote_mps; - control = 0; while (len > 0) { size_t buflen; if (len > pi->remote_mps) { - control |= L2CAP_SDU_CONTINUE; + control = L2CAP_SDU_CONTINUE; buflen = pi->remote_mps; } else { - control |= L2CAP_SDU_END; + control = L2CAP_SDU_END; buflen = len; } @@ -1658,7 +1657,6 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz __skb_queue_tail(&sar_queue, skb); len -= buflen; size += buflen; - control = 0; } skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk)); if (sk->sk_send_head == NULL) -- cgit v1.2.3-70-g09d2 From 59203a21a56c53afeb6f45e059299e6f1437f30f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:43 -0300 Subject: Bluetooth: Fix errors reported by checkpatch.pl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index cfb18cd9756..2a981de071d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1400,7 +1400,7 @@ static int l2cap_ertm_send(struct sock *sk) return 0; while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) && - !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) { + !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) { if (pi->remote_max_tx && bt_cb(skb)->retries == pi->remote_max_tx) { @@ -1490,9 +1490,8 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in struct sk_buff **frag; int err, sent = 0; - if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { + if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) return -EFAULT; - } sent += count; len -= count; @@ -3347,7 +3346,7 @@ static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_ if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb)) break; - } while((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb))); + } while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb))); __skb_queue_tail(SREJ_QUEUE(sk), skb); } @@ -3446,7 +3445,7 @@ static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) struct sk_buff *skb; u16 control; - while((skb = skb_peek(SREJ_QUEUE(sk)))) { + while ((skb = skb_peek(SREJ_QUEUE(sk)))) { if (bt_cb(skb)->tx_seq != tx_seq) break; @@ -3465,7 +3464,7 @@ static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq) struct srej_list *l, *tmp; u16 control; - list_for_each_entry_safe(l,tmp, SREJ_LIST(sk), list) { + list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { if (l->tx_seq == tx_seq) { list_del(&l->list); kfree(l); -- cgit v1.2.3-70-g09d2 From 0301ef04b5f49a95681694fc0d75af9441faa919 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 5 May 2010 20:56:43 -0300 Subject: Bluetooth: Remove set of SrejSaveReqSeq under receipt of REJ frame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That action is not specified by the ERTM spec, so removing it. 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, 1 insertion(+), 3 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 2a981de071d..d0d03302e14 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3670,10 +3670,8 @@ static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control) pi->next_tx_seq = pi->expected_ack_seq; l2cap_ertm_send(sk); - if (pi->conn_state & L2CAP_CONN_WAIT_F) { - pi->srej_save_reqseq = tx_seq; + if (pi->conn_state & L2CAP_CONN_WAIT_F) pi->conn_state |= L2CAP_CONN_REJ_ACT; - } } } static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control) -- cgit v1.2.3-70-g09d2 From a2e12a2a312f816d5970b0c809d43b399fbfe90c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 5 May 2010 19:58:27 -0300 Subject: Bluetooth: Remove unneeded control vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trivial clean up. 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, 4 insertions(+), 10 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index d0d03302e14..5a5203f0364 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1239,7 +1239,6 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l static void l2cap_monitor_timeout(unsigned long arg) { struct sock *sk = (void *) arg; - u16 control; bh_lock_sock(sk); if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { @@ -1251,15 +1250,13 @@ static void l2cap_monitor_timeout(unsigned long arg) l2cap_pi(sk)->retry_count++; __mod_monitor_timer(); - control = L2CAP_CTRL_POLL; - l2cap_send_rr_or_rnr(l2cap_pi(sk), control); + l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL); bh_unlock_sock(sk); } static void l2cap_retrans_timeout(unsigned long arg) { struct sock *sk = (void *) arg; - u16 control; bh_lock_sock(sk); l2cap_pi(sk)->retry_count = 1; @@ -1267,8 +1264,7 @@ static void l2cap_retrans_timeout(unsigned long arg) l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; - control = L2CAP_CTRL_POLL; - l2cap_send_rr_or_rnr(l2cap_pi(sk), control); + l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL); bh_unlock_sock(sk); } @@ -3716,10 +3712,8 @@ static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control) if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) { del_timer(&pi->retrans_timer); - if (rx_control & L2CAP_CTRL_POLL) { - u16 control = L2CAP_CTRL_FINAL; - l2cap_send_rr_or_rnr(pi, control); - } + if (rx_control & L2CAP_CTRL_POLL) + l2cap_send_rr_or_rnr(pi, L2CAP_CTRL_FINAL); return; } -- cgit v1.2.3-70-g09d2 From 9b16dc6551cbde65d0ac525af3c46efab53a2c46 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 5 May 2010 20:05:57 -0300 Subject: Bluetooth: Check if we really are in WAIT_F when F bit comes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit F-bit set should be processed only if we are in the WAIT_F state. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 5a5203f0364..eb5cb29115a 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3503,7 +3503,8 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); - if (L2CAP_CTRL_FINAL & rx_control) { + if (L2CAP_CTRL_FINAL & rx_control && + l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { del_timer(&pi->monitor_timer); if (pi->unacked_frames > 0) __mod_retrans_timer(); @@ -3727,7 +3728,8 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str { BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); - if (L2CAP_CTRL_FINAL & rx_control) { + if (L2CAP_CTRL_FINAL & rx_control && + l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { del_timer(&l2cap_pi(sk)->monitor_timer); if (l2cap_pi(sk)->unacked_frames > 0) __mod_retrans_timer(); -- cgit v1.2.3-70-g09d2 From ff12fd643334071084b6145cad3793bb6c956638 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 5 May 2010 22:09:15 -0300 Subject: Bluetooth: Fix lockdep annotation on ERTM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A spin_lock_init() call was missing. :) Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita 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 eb5cb29115a..6b08f4d7c87 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1622,7 +1622,7 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz u16 control; size_t size = 0; - __skb_queue_head_init(&sar_queue); + skb_queue_head_init(&sar_queue); control = L2CAP_SDU_START; skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len); if (IS_ERR(skb)) -- cgit v1.2.3-70-g09d2 From 9a9c6a34416b3743c09c00f3d6708d9df3c21629 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:43 -0300 Subject: Bluetooth: Make hci_send_acl() void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hci_send_acl can't fail, so we can make it void. This patch changes that and all the funcions that use hci_send_acl(). That change exposed a bug on sending connectionless data. We were not reporting the lenght send back to the user space. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 4 +-- net/bluetooth/l2cap.c | 73 +++++++++++++++------------------------- 3 files changed, 30 insertions(+), 49 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9830a88f487..4511df2a0d7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -636,7 +636,7 @@ int hci_register_notifier(struct notifier_block *nb); int hci_unregister_notifier(struct notifier_block *nb); int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); -int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); +void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1c9aef97f51..904f1e8a7a3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1260,7 +1260,7 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags) hdr->dlen = cpu_to_le16(len); } -int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) +void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) { struct hci_dev *hdev = conn->hdev; struct sk_buff *list; @@ -1303,7 +1303,7 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) tasklet_schedule(&hdev->tx_task); - return 0; + return; } EXPORT_SYMBOL(hci_send_acl); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 6b08f4d7c87..7e74d5be16e 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -330,19 +330,19 @@ static inline u8 l2cap_get_ident(struct l2cap_conn *conn) return id; } -static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data) +static inline void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data) { struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); BT_DBG("code 0x%2.2x", code); if (!skb) - return -ENOMEM; + return; - return hci_send_acl(conn->hcon, skb, 0); + hci_send_acl(conn->hcon, skb, 0); } -static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) +static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) { struct sk_buff *skb; struct l2cap_hdr *lh; @@ -369,7 +369,7 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) skb = bt_skb_alloc(count, GFP_ATOMIC); if (!skb) - return -ENOMEM; + return; lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE); @@ -381,10 +381,10 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) put_unaligned_le16(fcs, skb_put(skb, 2)); } - return hci_send_acl(pi->conn->hcon, skb, 0); + hci_send_acl(pi->conn->hcon, skb, 0); } -static inline int l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) +static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) { if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) control |= L2CAP_SUPER_RCV_NOT_READY; @@ -393,7 +393,7 @@ static inline int l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; - return l2cap_send_sframe(pi, control); + l2cap_send_sframe(pi, control); } static void l2cap_do_start(struct sock *sk) @@ -1289,18 +1289,13 @@ static void l2cap_drop_acked_frames(struct sock *sk) return; } -static inline int l2cap_do_send(struct sock *sk, struct sk_buff *skb) +static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb) { struct l2cap_pinfo *pi = l2cap_pi(sk); - int err; BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len); - err = hci_send_acl(pi->conn->hcon, skb, 0); - if (err < 0) - kfree_skb(skb); - - return err; + hci_send_acl(pi->conn->hcon, skb, 0); } static int l2cap_streaming_send(struct sock *sk) @@ -1308,7 +1303,6 @@ static int l2cap_streaming_send(struct sock *sk) struct sk_buff *skb, *tx_skb; struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; - int err; while ((skb = sk->sk_send_head)) { tx_skb = skb_clone(skb, GFP_ATOMIC); @@ -1322,11 +1316,7 @@ static int l2cap_streaming_send(struct sock *sk) put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); } - err = l2cap_do_send(sk, tx_skb); - if (err < 0) { - l2cap_send_disconn_req(pi->conn, sk); - return err; - } + l2cap_do_send(sk, tx_skb); pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; @@ -1346,7 +1336,6 @@ static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq) struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb, *tx_skb; u16 control, fcs; - int err; skb = skb_peek(TX_QUEUE(sk)); do { @@ -1375,11 +1364,7 @@ static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq) put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); } - err = l2cap_do_send(sk, tx_skb); - if (err < 0) { - l2cap_send_disconn_req(pi->conn, sk); - return err; - } + l2cap_do_send(sk, tx_skb); break; } while(1); return 0; @@ -1390,7 +1375,7 @@ static int l2cap_ertm_send(struct sock *sk) struct sk_buff *skb, *tx_skb; struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; - int err, nsent = 0; + int nsent = 0; if (pi->conn_state & L2CAP_CONN_WAIT_F) return 0; @@ -1423,11 +1408,8 @@ static int l2cap_ertm_send(struct sock *sk) put_unaligned_le16(fcs, skb->data + tx_skb->len - 2); } - err = l2cap_do_send(sk, tx_skb); - if (err < 0) { - l2cap_send_disconn_req(pi->conn, sk); - return err; - } + l2cap_do_send(sk, tx_skb); + __mod_retrans_timer(); bt_cb(skb)->tx_seq = pi->next_tx_seq; @@ -1447,7 +1429,7 @@ static int l2cap_ertm_send(struct sock *sk) return nsent; } -static int l2cap_send_ack(struct l2cap_pinfo *pi) +static void l2cap_send_ack(struct l2cap_pinfo *pi) { struct sock *sk = (struct sock *)pi; u16 control = 0; @@ -1456,15 +1438,15 @@ static int l2cap_send_ack(struct l2cap_pinfo *pi) if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; - return l2cap_send_sframe(pi, control); + l2cap_send_sframe(pi, control); + return; } else if (l2cap_ertm_send(sk) == 0) { control |= L2CAP_SUPER_RCV_READY; - return l2cap_send_sframe(pi, control); + l2cap_send_sframe(pi, control); } - return 0; } -static int l2cap_send_srejtail(struct sock *sk) +static void l2cap_send_srejtail(struct sock *sk) { struct srej_list *tail; u16 control; @@ -1476,8 +1458,6 @@ static int l2cap_send_srejtail(struct sock *sk) control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; l2cap_send_sframe(l2cap_pi(sk), control); - - return 0; } static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) @@ -1687,10 +1667,12 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms /* Connectionless channel */ if (sk->sk_type == SOCK_DGRAM) { skb = l2cap_create_connless_pdu(sk, msg, len); - if (IS_ERR(skb)) + if (IS_ERR(skb)) { err = PTR_ERR(skb); - else - err = l2cap_do_send(sk, skb); + } else { + l2cap_do_send(sk, skb); + err = len; + } goto done; } @@ -1709,9 +1691,8 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms goto done; } - err = l2cap_do_send(sk, skb); - if (!err) - err = len; + l2cap_do_send(sk, skb); + err = len; break; case L2CAP_MODE_ERTM: -- cgit v1.2.3-70-g09d2 From f11d676da4059c7888efca810ab300b931736a26 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:44 -0300 Subject: Bluetooth: Refactor l2cap_retransmit_frame() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the code flow cleaner and changes the function to void. It also fixes a potential NULL dereference with skb. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 53 ++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 7e74d5be16e..1c35c328181 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1331,43 +1331,44 @@ static int l2cap_streaming_send(struct sock *sk) return 0; } -static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq) +static void l2cap_retransmit_frame(struct sock *sk, u8 tx_seq) { struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb, *tx_skb; u16 control, fcs; skb = skb_peek(TX_QUEUE(sk)); - do { - if (bt_cb(skb)->tx_seq != tx_seq) { - if (skb_queue_is_last(TX_QUEUE(sk), skb)) - break; - skb = skb_queue_next(TX_QUEUE(sk), skb); - continue; - } + if (!skb) + return; - if (pi->remote_max_tx && - bt_cb(skb)->retries == pi->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, sk); + do { + if (bt_cb(skb)->tx_seq == tx_seq) break; - } - tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->retries++; - control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); - 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 (skb_queue_is_last(TX_QUEUE(sk), skb)) + return; - if (pi->fcs == L2CAP_FCS_CRC16) { - fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); - put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); - } + } while ((skb = skb_queue_next(TX_QUEUE(sk), skb))); - l2cap_do_send(sk, tx_skb); - break; - } while(1); - return 0; + if (pi->remote_max_tx && + bt_cb(skb)->retries == pi->remote_max_tx) { + l2cap_send_disconn_req(pi->conn, sk); + return; + } + + tx_skb = skb_clone(skb, GFP_ATOMIC); + bt_cb(skb)->retries++; + control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); + 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) { + fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); + put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); + } + + l2cap_do_send(sk, tx_skb); } static int l2cap_ertm_send(struct sock *sk) -- cgit v1.2.3-70-g09d2 From 18778a63ddc83bc89bda3b119fb02eb121512a66 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:44 -0300 Subject: Bluetooth: Implement missing parts of the Invalid Frame Detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a plenty of situation where ERTM shall close the channel, this commit treats the cases regarding Invalid Frame Detection. It create one reassembly SDU function for ERTM and other for Streaming Mode to make the Invalid Frame Detection handling less complex. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 112 insertions(+), 7 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 1c35c328181..cfd67241931 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3329,12 +3329,111 @@ static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_ __skb_queue_tail(SREJ_QUEUE(sk), skb); } -static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) +static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sk_buff *_skb; + int err = 0; + + switch (control & L2CAP_CTRL_SAR) { + case L2CAP_SDU_UNSEGMENTED: + if (pi->conn_state & L2CAP_CONN_SAR_SDU) + goto drop; + + err = sock_queue_rcv_skb(sk, skb); + if (!err) + return err; + + break; + + case L2CAP_SDU_START: + if (pi->conn_state & L2CAP_CONN_SAR_SDU) + goto drop; + + pi->sdu_len = get_unaligned_le16(skb->data); + skb_pull(skb, 2); + + if (pi->sdu_len > pi->imtu) + goto disconnect; + + pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); + if (!pi->sdu) { + err = -ENOMEM; + break; + } + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + pi->conn_state |= L2CAP_CONN_SAR_SDU; + pi->partial_sdu_len = skb->len; + break; + + case L2CAP_SDU_CONTINUE: + if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + goto disconnect; + + if (!pi->sdu) + goto disconnect; + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + pi->partial_sdu_len += skb->len; + if (pi->partial_sdu_len > pi->sdu_len) + goto drop; + + break; + + case L2CAP_SDU_END: + if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + goto disconnect; + + if (!pi->sdu) + goto disconnect; + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + + pi->conn_state &= ~L2CAP_CONN_SAR_SDU; + pi->partial_sdu_len += skb->len; + + if (pi->partial_sdu_len > pi->imtu) + goto drop; + + if (pi->partial_sdu_len != pi->sdu_len) + goto drop; + + _skb = skb_clone(pi->sdu, GFP_ATOMIC); + err = sock_queue_rcv_skb(sk, _skb); + if (err < 0) + kfree_skb(_skb); + + kfree_skb(pi->sdu); + break; + } + + kfree_skb(skb); + return err; + +drop: + kfree_skb(pi->sdu); + pi->sdu = NULL; + +disconnect: + l2cap_send_disconn_req(pi->conn, sk); + kfree_skb(skb); + return 0; +} + +static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) { struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *_skb; int err = -EINVAL; + /* + * TODO: We have to notify the userland if some data is lost with the + * Streaming Mode. + */ + switch (control & L2CAP_CTRL_SAR) { case L2CAP_SDU_UNSEGMENTED: if (pi->conn_state & L2CAP_CONN_SAR_SDU) { @@ -3429,7 +3528,7 @@ static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) skb = skb_dequeue(SREJ_QUEUE(sk)); control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; - l2cap_sar_reassembly_sdu(sk, skb, control); + l2cap_ertm_reassembly_sdu(sk, skb, control); l2cap_pi(sk)->buffer_seq_srej = (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; tx_seq++; @@ -3566,7 +3665,7 @@ expected: pi->buffer_seq = (pi->buffer_seq + 1) % 64; - err = l2cap_sar_reassembly_sdu(sk, skb, rx_control); + err = l2cap_ertm_reassembly_sdu(sk, skb, rx_control); if (err < 0) return err; @@ -3790,8 +3889,10 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk * Receiver will miss it and start proper recovery * procedures and ask retransmission. */ - if (len > pi->mps) + if (len > pi->mps) { + l2cap_send_disconn_req(pi->conn, sk); goto drop; + } if (l2cap_check_fcs(pi, skb)) goto drop; @@ -3813,13 +3914,17 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk } if (__is_iframe(control)) { - if (len < 4) + if (len < 4) { + l2cap_send_disconn_req(pi->conn, sk); goto drop; + } l2cap_data_channel_iframe(sk, control, skb); } else { - if (len != 0) + if (len != 0) { + l2cap_send_disconn_req(pi->conn, sk); goto drop; + } l2cap_data_channel_sframe(sk, control, skb); } @@ -3850,7 +3955,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk else pi->expected_tx_seq = (tx_seq + 1) % 64; - l2cap_sar_reassembly_sdu(sk, skb, control); + l2cap_streaming_reassembly_sdu(sk, skb, control); goto done; -- cgit v1.2.3-70-g09d2 From 9b53350d3cf5b330c3261d89b5e62a2dc25c5653 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Sat, 1 May 2010 16:15:44 -0300 Subject: Bluetooth: Completes the I-frame tx_seq check logic on RECV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add checks for invalid tx_seq and fixes the duplicated tx_seq check. Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index cfd67241931..481cec22ef9 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3302,7 +3302,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) } } -static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) +static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) { struct sk_buff *next_skb; @@ -3312,13 +3312,16 @@ static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_ next_skb = skb_peek(SREJ_QUEUE(sk)); if (!next_skb) { __skb_queue_tail(SREJ_QUEUE(sk), skb); - return; + return 0; } do { + if (bt_cb(next_skb)->tx_seq == tx_seq) + return -EINVAL; + if (bt_cb(next_skb)->tx_seq > tx_seq) { __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb); - return; + return 0; } if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb)) @@ -3327,6 +3330,8 @@ static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_ } while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb))); __skb_queue_tail(SREJ_QUEUE(sk), skb); + + return 0; } static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) @@ -3579,6 +3584,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 num_to_ack = (pi->tx_win/6) + 1; int err = 0; @@ -3598,6 +3604,16 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str if (tx_seq == pi->expected_tx_seq) goto expected; + tx_seq_offset = (tx_seq - pi->buffer_seq) % 64; + if (tx_seq_offset < 0) + tx_seq_offset += 64; + + /* invalid tx_seq */ + if (tx_seq_offset >= pi->tx_win) { + l2cap_send_disconn_req(pi->conn, sk); + goto drop; + } + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { struct srej_list *first; @@ -3617,7 +3633,10 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str } } else { struct srej_list *l; - l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + + /* duplicated tx_seq */ + if (l2cap_add_to_srej_queue(sk, skb, tx_seq, sar) < 0) + goto drop; list_for_each_entry(l, SREJ_LIST(sk), list) { if (l->tx_seq == tx_seq) { @@ -3628,6 +3647,15 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str l2cap_send_srejframe(sk, tx_seq); } } else { + expected_tx_seq_offset = + (pi->expected_tx_seq - pi->buffer_seq) % 64; + if (expected_tx_seq_offset < 0) + expected_tx_seq_offset += 64; + + /* duplicated tx_seq */ + if (tx_seq_offset < expected_tx_seq_offset) + goto drop; + pi->conn_state |= L2CAP_CONN_SREJ_SENT; INIT_LIST_HEAD(SREJ_LIST(sk)); @@ -3676,6 +3704,10 @@ expected: l2cap_send_ack(pi); return 0; + +drop: + kfree_skb(skb); + return 0; } static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) -- cgit v1.2.3-70-g09d2 From 1890d36bb556a27684ad29654a9898ab9a5f57ee Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:44 -0300 Subject: Bluetooth: Implement Local Busy Condition handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supports Local Busy condition handling through a waitqueue that wake ups each 200ms and try to push the packets to the upper layer. If it can push all the queue then it leaves the Local Busy state. The patch modifies the behaviour of l2cap_ertm_reassembly_sdu() to support retry of the push operation. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 6 ++ net/bluetooth/l2cap.c | 187 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 172 insertions(+), 21 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 8942c2ffc58..d0185cc04c1 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -35,6 +35,7 @@ #define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ #define L2CAP_DEFAULT_MAX_PDU_SIZE 672 #define L2CAP_DEFAULT_ACK_TO 200 +#define L2CAP_LOCAL_BUSY_TRIES 12 #define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */ #define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */ @@ -294,6 +295,7 @@ struct l2cap_conn { #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) #define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) #define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue) +#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue) #define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list) struct srej_list { @@ -356,6 +358,8 @@ struct l2cap_pinfo { struct timer_list ack_timer; struct sk_buff_head tx_queue; struct sk_buff_head srej_queue; + struct sk_buff_head busy_queue; + struct work_struct busy_work; struct srej_list srej_l; struct l2cap_conn *conn; struct sock *next_c; @@ -383,6 +387,8 @@ struct l2cap_pinfo { #define L2CAP_CONN_LOCAL_BUSY 0x0040 #define L2CAP_CONN_REJ_ACT 0x0080 #define L2CAP_CONN_SEND_FBIT 0x0100 +#define L2CAP_CONN_RNR_SENT 0x0200 +#define L2CAP_CONN_SAR_RETRY 0x0400 #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 481cec22ef9..103e4b54a86 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -68,10 +68,14 @@ static u8 l2cap_fixed_chan[8] = { 0x02, }; static const struct proto_ops l2cap_sock_ops; +static struct workqueue_struct *_busy_wq; + static struct bt_sock_list l2cap_sk_list = { .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) }; +static void l2cap_busy_work(struct work_struct *work); + 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); @@ -386,9 +390,10 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) { - if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) + if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; - else + pi->conn_state |= L2CAP_CONN_RNR_SENT; + } else control |= L2CAP_SUPER_RCV_READY; control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; @@ -816,6 +821,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; skb_queue_head_init(TX_QUEUE(sk)); skb_queue_head_init(SREJ_QUEUE(sk)); + skb_queue_head_init(BUSY_QUEUE(sk)); INIT_LIST_HEAD(SREJ_LIST(sk)); } @@ -1439,6 +1445,7 @@ static void l2cap_send_ack(struct l2cap_pinfo *pi) if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; + pi->conn_state |= L2CAP_CONN_RNR_SENT; l2cap_send_sframe(pi, control); return; } else if (l2cap_ertm_send(sk) == 0) { @@ -2279,6 +2286,9 @@ static inline void l2cap_ertm_init(struct sock *sk) l2cap_ack_timeout, (unsigned long) sk); __skb_queue_head_init(SREJ_QUEUE(sk)); + __skb_queue_head_init(BUSY_QUEUE(sk)); + + INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); } static int l2cap_mode_supported(__u8 mode, __u32 feat_mask) @@ -3046,6 +3056,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd 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); @@ -3077,6 +3088,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd 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); @@ -3287,6 +3299,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL; l2cap_send_sframe(pi, control); + pi->conn_state |= L2CAP_CONN_RNR_SENT; pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; } @@ -3338,7 +3351,7 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c { struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *_skb; - int err = 0; + int err; switch (control & L2CAP_CTRL_SAR) { case L2CAP_SDU_UNSEGMENTED: @@ -3356,16 +3369,18 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c goto drop; pi->sdu_len = get_unaligned_le16(skb->data); - skb_pull(skb, 2); if (pi->sdu_len > pi->imtu) goto disconnect; pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); - if (!pi->sdu) { - err = -ENOMEM; - break; - } + if (!pi->sdu) + return -ENOMEM; + + /* pull sdu_len bytes only after alloc, because of Local Busy + * condition we have to be sure that this will be executed + * only once, i.e., when alloc does not fail */ + skb_pull(skb, 2); memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); @@ -3395,28 +3410,40 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c if (!pi->sdu) goto disconnect; - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) { + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); - pi->conn_state &= ~L2CAP_CONN_SAR_SDU; - pi->partial_sdu_len += skb->len; + pi->partial_sdu_len += skb->len; - if (pi->partial_sdu_len > pi->imtu) - goto drop; + if (pi->partial_sdu_len > pi->imtu) + goto drop; - if (pi->partial_sdu_len != pi->sdu_len) - goto drop; + if (pi->partial_sdu_len != pi->sdu_len) + goto drop; + } _skb = skb_clone(pi->sdu, GFP_ATOMIC); + if (!_skb) { + pi->conn_state |= L2CAP_CONN_SAR_RETRY; + return -ENOMEM; + } + err = sock_queue_rcv_skb(sk, _skb); - if (err < 0) + if (err < 0) { kfree_skb(_skb); + pi->conn_state |= L2CAP_CONN_SAR_RETRY; + return err; + } + + pi->conn_state &= ~L2CAP_CONN_SAR_RETRY; + pi->conn_state &= ~L2CAP_CONN_SAR_SDU; kfree_skb(pi->sdu); break; } kfree_skb(skb); - return err; + return 0; drop: kfree_skb(pi->sdu); @@ -3428,6 +3455,115 @@ disconnect: return 0; } +static void l2cap_busy_work(struct work_struct *work) +{ + DECLARE_WAITQUEUE(wait, current); + struct l2cap_pinfo *pi = + container_of(work, struct l2cap_pinfo, busy_work); + struct sock *sk = (struct sock *)pi; + int n_tries = 0, timeo = HZ/5, err; + struct sk_buff *skb; + u16 control; + + lock_sock(sk); + + add_wait_queue(sk->sk_sleep, &wait); + while ((skb = skb_peek(BUSY_QUEUE(sk)))) { + set_current_state(TASK_INTERRUPTIBLE); + + if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { + err = -EBUSY; + l2cap_send_disconn_req(pi->conn, sk); + goto done; + } + + if (!timeo) + timeo = HZ/5; + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + goto done; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + 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; + } + + if (!skb) + 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; + + set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sk_sleep, &wait); + + release_sock(sk); +} + +static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) +{ + struct l2cap_pinfo *pi = l2cap_pi(sk); + int sctrl, err; + + 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; + } + + err = l2cap_ertm_reassembly_sdu(sk, skb, control); + if (err >= 0) { + pi->buffer_seq = (pi->buffer_seq + 1) % 64; + return err; + } + + /* Busy Condition */ + pi->conn_state |= L2CAP_CONN_LOCAL_BUSY; + bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; + __skb_queue_tail(BUSY_QUEUE(sk), skb); + + sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + sctrl |= L2CAP_SUPER_RCV_NOT_READY; + l2cap_send_sframe(pi, sctrl); + + pi->conn_state |= L2CAP_CONN_RNR_SENT; + + queue_work(_busy_wq, &pi->busy_work); + + return err; +} + static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) { struct l2cap_pinfo *pi = l2cap_pi(sk); @@ -3614,6 +3750,9 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str goto drop; } + if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY) + goto drop; + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { struct srej_list *first; @@ -3662,6 +3801,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str pi->buffer_seq_srej = pi->buffer_seq; __skb_queue_head_init(SREJ_QUEUE(sk)); + __skb_queue_head_init(BUSY_QUEUE(sk)); l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); pi->conn_state |= L2CAP_CONN_SEND_PBIT; @@ -3691,11 +3831,9 @@ expected: } } - pi->buffer_seq = (pi->buffer_seq + 1) % 64; - - err = l2cap_ertm_reassembly_sdu(sk, skb, rx_control); + err = l2cap_push_rx_skb(sk, skb, rx_control); if (err < 0) - return err; + return 0; __mod_ack_timer(); @@ -4406,6 +4544,10 @@ static int __init l2cap_init(void) if (err < 0) return err; + _busy_wq = create_singlethread_workqueue("l2cap"); + if (!_busy_wq) + goto error; + err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops); if (err < 0) { BT_ERR("L2CAP socket registration failed"); @@ -4440,6 +4582,9 @@ static void __exit l2cap_exit(void) { debugfs_remove(l2cap_debugfs); + flush_workqueue(_busy_wq); + destroy_workqueue(_busy_wq); + if (bt_sock_unregister(BTPROTO_L2CAP) < 0) BT_ERR("L2CAP socket unregistration failed"); -- cgit v1.2.3-70-g09d2 From 6161c0382bbab883a634d284f7367a88bbe88534 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:44 -0300 Subject: Bluetooth: Add wait_queue to wait ack of all sent packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To guarantee that all packets we sent were received we need to wait for theirs ack before shutdown the socket. Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 103e4b54a86..9d514f9dbc0 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1242,6 +1242,37 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l return 0; } +static int __l2cap_wait_ack(struct sock *sk) +{ + DECLARE_WAITQUEUE(wait, current); + int err = 0; + int timeo = HZ/5; + + add_wait_queue(sk->sk_sleep, &wait); + while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) { + set_current_state(TASK_INTERRUPTIBLE); + + if (!timeo) + timeo = HZ/5; + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + err = sock_error(sk); + if (err) + break; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sk_sleep, &wait); + return err; +} + static void l2cap_monitor_timeout(unsigned long arg) { struct sock *sk = (void *) arg; @@ -2059,6 +2090,9 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) lock_sock(sk); if (!sk->sk_shutdown) { + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + err = __l2cap_wait_ack(sk); + sk->sk_shutdown = SHUTDOWN_MASK; l2cap_sock_clear_timer(sk); __l2cap_sock_close(sk, 0); -- cgit v1.2.3-70-g09d2 From dfc909befbfe967bd7f46ef33b6969c1b7f3cf42 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:45 -0300 Subject: Bluetooth: Fix race condition on l2cap_ertm_send() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit l2cap_ertm_send() can be called both from user context and bottom half context. The socket locks for that contexts are different, the user context uses a mutex(which can sleep) and the second one uses a spinlock_bh. That creates a race condition when we have interruptions on both contexts at the same time. The better way to solve this is to add a new spinlock to lock l2cap_ertm_send() and the vars it access. The other solution was to defer l2cap_ertm_send() with a workqueue, but we the sending process already has one defer on the hci layer. It's not a good idea add another one. The patch refactor the code to create l2cap_retransmit_frames(), then we encapulate the lock of l2cap_ertm_send() for some call. It also changes l2cap_retransmit_frame() to l2cap_retransmit_one_frame() to avoid confusion Signed-off-by: Gustavo F. Padovan Reviewed-by: João Paulo Rechi Vita Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap.c | 99 ++++++++++++++++++++++++++++--------------- 2 files changed, 67 insertions(+), 33 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d0185cc04c1..7c695bfd853 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -353,6 +353,7 @@ 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 9d514f9dbc0..fe663e9c668 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1368,7 +1368,7 @@ static int l2cap_streaming_send(struct sock *sk) return 0; } -static void l2cap_retransmit_frame(struct sock *sk, u8 tx_seq) +static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) { struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb, *tx_skb; @@ -1467,10 +1467,29 @@ static int l2cap_ertm_send(struct sock *sk) return nsent; } +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; +} + 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; @@ -1479,10 +1498,17 @@ static void l2cap_send_ack(struct l2cap_pinfo *pi) pi->conn_state |= L2CAP_CONN_RNR_SENT; l2cap_send_sframe(pi, control); return; - } else if (l2cap_ertm_send(sk) == 0) { - control |= L2CAP_SUPER_RCV_READY; - l2cap_send_sframe(pi, control); } + + spin_lock_bh(&pi->send_lock); + nframes = l2cap_ertm_send(sk); + spin_unlock_bh(&pi->send_lock); + + if (nframes > 0) + return; + + control |= L2CAP_SUPER_RCV_READY; + l2cap_send_sframe(pi, control); } static void l2cap_send_srejtail(struct sock *sk) @@ -1673,8 +1699,10 @@ 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; } @@ -1745,8 +1773,15 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms goto done; } __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); @@ -1754,10 +1789,13 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms goto done; } - if (pi->mode == L2CAP_MODE_STREAMING) + if (pi->mode == L2CAP_MODE_STREAMING) { err = l2cap_streaming_send(sk); - else + } else { + spin_lock_bh(&pi->send_lock); err = l2cap_ertm_send(sk); + spin_unlock_bh(&pi->send_lock); + } if (err >= 0) err = len; @@ -2321,6 +2359,7 @@ 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); } @@ -3340,7 +3379,9 @@ 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(); + 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) { @@ -3857,12 +3898,8 @@ expected: if (rx_control & L2CAP_CTRL_FINAL) { if (pi->conn_state & L2CAP_CONN_REJ_ACT) pi->conn_state &= ~L2CAP_CONN_REJ_ACT; - else { - if (!skb_queue_empty(TX_QUEUE(sk))) - sk->sk_send_head = TX_QUEUE(sk)->next; - pi->next_tx_seq = pi->expected_ack_seq; - l2cap_ertm_send(sk); - } + else + l2cap_retransmit_frames(sk); } err = l2cap_push_rx_skb(sk, skb, rx_control); @@ -3907,12 +3944,8 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) if (pi->conn_state & L2CAP_CONN_REJ_ACT) pi->conn_state &= ~L2CAP_CONN_REJ_ACT; - else { - if (!skb_queue_empty(TX_QUEUE(sk))) - sk->sk_send_head = TX_QUEUE(sk)->next; - pi->next_tx_seq = pi->expected_ack_seq; - l2cap_ertm_send(sk); - } + else + l2cap_retransmit_frames(sk); } else { if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && @@ -3920,10 +3953,13 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) __mod_retrans_timer(); pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - if (pi->conn_state & L2CAP_CONN_SREJ_SENT) + if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { l2cap_send_ack(pi); - else + } else { + spin_lock_bh(&pi->send_lock); l2cap_ertm_send(sk); + spin_unlock_bh(&pi->send_lock); + } } } @@ -3940,17 +3976,10 @@ static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control) if (rx_control & L2CAP_CTRL_FINAL) { if (pi->conn_state & L2CAP_CONN_REJ_ACT) pi->conn_state &= ~L2CAP_CONN_REJ_ACT; - else { - if (!skb_queue_empty(TX_QUEUE(sk))) - sk->sk_send_head = TX_QUEUE(sk)->next; - pi->next_tx_seq = pi->expected_ack_seq; - l2cap_ertm_send(sk); - } + else + l2cap_retransmit_frames(sk); } else { - if (!skb_queue_empty(TX_QUEUE(sk))) - sk->sk_send_head = TX_QUEUE(sk)->next; - pi->next_tx_seq = pi->expected_ack_seq; - l2cap_ertm_send(sk); + l2cap_retransmit_frames(sk); if (pi->conn_state & L2CAP_CONN_WAIT_F) pi->conn_state |= L2CAP_CONN_REJ_ACT; @@ -3966,8 +3995,12 @@ 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); - l2cap_retransmit_frame(sk, tx_seq); + 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; pi->conn_state |= L2CAP_CONN_SREJ_ACT; @@ -3977,9 +4010,9 @@ static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control) pi->srej_save_reqseq == tx_seq) pi->conn_state &= ~L2CAP_CONN_SREJ_ACT; else - l2cap_retransmit_frame(sk, tx_seq); + l2cap_retransmit_one_frame(sk, tx_seq); } else { - l2cap_retransmit_frame(sk, tx_seq); + l2cap_retransmit_one_frame(sk, tx_seq); if (pi->conn_state & L2CAP_CONN_WAIT_F) { pi->srej_save_reqseq = tx_seq; pi->conn_state |= L2CAP_CONN_SREJ_ACT; -- cgit v1.2.3-70-g09d2 From 4178ba462a3e8ab5094e69606f01d9e95f2d5ea6 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 1 May 2010 16:15:45 -0300 Subject: Bluetooth: Prevents buffer overflow on l2cap_ertm_reassembly_sdu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The checks should be done before the the memcpy to avoid buffer overflow. Reported-by: João Paulo Rechi Vita 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 fe663e9c668..9ef01c32b3a 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3470,12 +3470,12 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c if (!pi->sdu) goto disconnect; - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); - pi->partial_sdu_len += skb->len; if (pi->partial_sdu_len > pi->sdu_len) goto drop; + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + break; case L2CAP_SDU_END: @@ -3486,8 +3486,6 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c goto disconnect; if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) { - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); - pi->partial_sdu_len += skb->len; if (pi->partial_sdu_len > pi->imtu) @@ -3495,6 +3493,8 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c if (pi->partial_sdu_len != pi->sdu_len) goto drop; + + memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); } _skb = skb_clone(pi->sdu, GFP_ATOMIC); -- cgit v1.2.3-70-g09d2 From 844c0972427ee5f661158160aaca10b22b3dda60 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 4 May 2010 23:16:01 -0300 Subject: Bluetooth: Fix spec error in the RemoteBusy Logic On the receipt of an RR(P=1) under RemoteBusy set to TRUE(on the RECV state table) we have to call sendIorRRorRNR(F=1) and just after set RemoteBusy to False. This leads to a freeze in the sending process since it's not allowed send data with RemoteBusy set to true and no one call SendPending-I-Frames after set RemoteBusy to false(The last action for that event). Actually sendIorRRorRNR() calls SendPending-I-Frames but at that moment RemoteBusy is still True and we cannot send any frame, after, no one calls SendPending-I-Frames again and the sending process stops. The solution here is to set RemoteBusy to false inside SendPending-I-Frames just before call SendPending-I-Frames. That will make SendPending-I-Frames able to send frames. This solution is similar to what RR(P=0)(F=0) on the RECV table and RR(P=1) on the SREJ_SENT table do. Actually doesn't make any sense call SendPending-I-Frames if we can send any frame, i. e., RemoteBusy is True. 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 9ef01c32b3a..ba49f9a3579 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -3379,6 +3379,8 @@ 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); @@ -3936,7 +3938,6 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) l2cap_send_srejtail(sk); } else { l2cap_send_i_or_rr_or_rnr(sk); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; } } else if (rx_control & L2CAP_CTRL_FINAL) { -- cgit v1.2.3-70-g09d2 From 2b0b05ddc04b6d45e71cd36405df512075786f1e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 10 May 2010 11:33:10 +0200 Subject: Bluetooth: Fix issues where sk_sleep() helper is needed now There were some left-overs that used sk->sk_sleep instead of the new sk_sleep() helper. 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 ba49f9a3579..673a3688671 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1248,7 +1248,7 @@ static int __l2cap_wait_ack(struct sock *sk) int err = 0; int timeo = HZ/5; - add_wait_queue(sk->sk_sleep, &wait); + add_wait_queue(sk_sleep(sk), &wait); while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) { set_current_state(TASK_INTERRUPTIBLE); @@ -1269,7 +1269,7 @@ static int __l2cap_wait_ack(struct sock *sk) break; } set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sk_sleep, &wait); + remove_wait_queue(sk_sleep(sk), &wait); return err; } @@ -3544,7 +3544,7 @@ static void l2cap_busy_work(struct work_struct *work) lock_sock(sk); - add_wait_queue(sk->sk_sleep, &wait); + add_wait_queue(sk_sleep(sk), &wait); while ((skb = skb_peek(BUSY_QUEUE(sk)))) { set_current_state(TASK_INTERRUPTIBLE); @@ -3603,7 +3603,7 @@ done: pi->conn_state &= ~L2CAP_CONN_RNR_SENT; set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sk_sleep, &wait); + remove_wait_queue(sk_sleep(sk), &wait); release_sock(sk); } -- cgit v1.2.3-70-g09d2 From 3fa21e07e6acefa31f974d57fba2b6920a7ebd1a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 17 May 2010 23:08:21 -0700 Subject: net: Remove unnecessary returns from void function()s This patch removes from net/ (but not any netfilter files) all the unnecessary return; statements that precede the last closing brace of void functions. It does not remove the returns that are immediately preceded by a label as gcc doesn't like that. Done via: $ grep -rP --include=*.[ch] -l "return;\n}" net/ | \ xargs perl -i -e 'local $/ ; while (<>) { s/\n[ \t\n]+return;\n}/\n}/g; print; }' Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/9p/trans_rdma.c | 1 - net/atm/br2684.c | 1 - net/atm/lec.c | 6 ------ net/atm/mpc.c | 32 -------------------------------- net/atm/mpoa_caches.c | 20 -------------------- net/bluetooth/hci_core.c | 2 -- net/bluetooth/l2cap.c | 3 --- net/bluetooth/rfcomm/tty.c | 2 -- net/bluetooth/sco.c | 1 - net/caif/caif_dev.c | 1 - net/can/bcm.c | 2 -- net/decnet/dn_dev.c | 3 --- net/decnet/dn_route.c | 1 - net/ipv4/cipso_ipv4.c | 2 -- net/ipv4/fib_trie.c | 2 -- net/ipv4/ip_gre.c | 1 - net/ipv4/ip_options.c | 1 - net/ipv4/ipmr.c | 1 - net/ipv6/ndisc.c | 2 -- net/ipv6/proc.c | 1 - net/ipv6/route.c | 2 -- net/irda/iriap.c | 2 -- net/irda/irnet/irnet_irda.c | 3 --- net/iucv/af_iucv.c | 1 - net/mac80211/debugfs.h | 1 - net/mac80211/mesh.c | 2 -- net/mac80211/mesh_hwmp.c | 1 - net/netlabel/netlabel_addrlist.h | 2 -- net/netlabel/netlabel_unlabeled.c | 1 - net/sched/cls_flow.c | 1 - net/sched/sch_hfsc.c | 1 - net/sched/sch_ingress.c | 1 - net/sched/sch_mq.c | 1 - net/sched/sch_multiq.c | 1 - net/sched/sch_prio.c | 1 - net/sched/sch_red.c | 1 - net/sctp/associola.c | 2 -- net/sctp/outqueue.c | 2 -- net/sctp/proc.c | 3 --- net/sctp/sm_sideeffect.c | 4 ---- net/sctp/ulpqueue.c | 2 -- net/sunrpc/clnt.c | 1 - net/sunrpc/svcsock.c | 1 - net/sunrpc/xprt.c | 1 - net/sunrpc/xprtsock.c | 4 ---- net/sysctl_net.c | 1 - net/wimax/stack.c | 2 -- net/xfrm/xfrm_policy.c | 1 - 48 files changed, 131 deletions(-) (limited to 'net/bluetooth/l2cap.c') diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 041101ab4aa..0ea20c30466 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c @@ -308,7 +308,6 @@ handle_recv(struct p9_client *client, struct p9_trans_rdma *rdma, req, err, status); rdma->state = P9_RDMA_FLUSHING; client->status = Disconnected; - return; } static void diff --git a/net/atm/br2684.c b/net/atm/br2684.c index d6c7ceaf13e..6719af6a59f 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -446,7 +446,6 @@ error: net_dev->stats.rx_errors++; free_skb: dev_kfree_skb(skb); - return; } /* diff --git a/net/atm/lec.c b/net/atm/lec.c index feeaf571847..d98bde1a0ac 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -161,8 +161,6 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev) skb_queue_tail(&sk->sk_receive_queue, skb2); sk->sk_data_ready(sk, skb2->len); } - - return; } #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ @@ -640,7 +638,6 @@ static void lec_set_multicast_list(struct net_device *dev) * by default, all multicast frames arrive over the bus. * eventually support selective multicast service */ - return; } static const struct net_device_ops lec_netdev_ops = { @@ -1199,8 +1196,6 @@ static void __exit lane_module_cleanup(void) dev_lec[i] = NULL; } } - - return; } module_init(lane_module_init); @@ -1334,7 +1329,6 @@ static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr, priv->lane2_ops->associate_indicator(dev, mac_addr, tlvs, sizeoftlvs); } - return; } /* diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 436f2e17765..622b471e14e 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -455,7 +455,6 @@ static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr, if (end_of_tlvs - tlvs != 0) pr_info("(%s) ignoring %Zd bytes of trailing TLV garbage\n", dev->name, end_of_tlvs - tlvs); - return; } /* @@ -684,8 +683,6 @@ static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev) if (in_entry == NULL && eg_entry == NULL) dprintk("(%s) unused vcc closed\n", dev->name); - - return; } static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) @@ -783,8 +780,6 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(new_skb); - - return; } static struct atmdev_ops mpc_ops = { /* only send is required */ @@ -873,8 +868,6 @@ static void send_set_mps_ctrl_addr(const char *addr, struct mpoa_client *mpc) mesg.type = SET_MPS_CTRL_ADDR; memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN); msg_to_mpoad(&mesg, mpc); - - return; } static void mpoad_close(struct atm_vcc *vcc) @@ -911,8 +904,6 @@ static void mpoad_close(struct atm_vcc *vcc) pr_info("(%s) going down\n", (mpc->dev) ? mpc->dev->name : ""); module_put(THIS_MODULE); - - return; } /* @@ -1122,7 +1113,6 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) pr_info("(%s) entry already in resolving state\n", (mpc->dev) ? mpc->dev->name : ""); mpc->in_ops->put(entry); - return; } /* @@ -1166,7 +1156,6 @@ static void check_qos_and_open_shortcut(struct k_message *msg, } else memset(&msg->qos, 0, sizeof(struct atm_qos)); msg_to_mpoad(msg, client); - return; } static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) @@ -1240,8 +1229,6 @@ static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) mpc->in_ops->put(entry); entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask); } while (entry != NULL); - - return; } static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) @@ -1260,8 +1247,6 @@ static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) write_unlock_irq(&mpc->egress_lock); mpc->eg_ops->put(entry); - - return; } static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry) @@ -1295,8 +1280,6 @@ static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry) skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); dprintk("exiting\n"); - - return; } /* @@ -1325,8 +1308,6 @@ static void mps_death(struct k_message *msg, struct mpoa_client *mpc) mpc->in_ops->destroy_cache(mpc); mpc->eg_ops->destroy_cache(mpc); - - return; } static void MPOA_cache_impos_rcvd(struct k_message *msg, @@ -1353,8 +1334,6 @@ static void MPOA_cache_impos_rcvd(struct k_message *msg, write_unlock_irq(&mpc->egress_lock); mpc->eg_ops->put(entry); - - return; } static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, @@ -1392,8 +1371,6 @@ static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, pr_info("(%s) targetless LE_ARP request failed\n", mpc->dev->name); } - - return; } static void set_mps_mac_addr_rcvd(struct k_message *msg, @@ -1409,8 +1386,6 @@ static void set_mps_mac_addr_rcvd(struct k_message *msg, return; } client->number_of_mps_macs = 1; - - return; } /* @@ -1436,7 +1411,6 @@ static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action) msg->type = action; msg_to_mpoad(msg, mpc); - return; } static void mpc_timer_refresh(void) @@ -1445,8 +1419,6 @@ static void mpc_timer_refresh(void) mpc_timer.data = mpc_timer.expires; mpc_timer.function = mpc_cache_check; add_timer(&mpc_timer); - - return; } static void mpc_cache_check(unsigned long checking_time) @@ -1471,8 +1443,6 @@ static void mpc_cache_check(unsigned long checking_time) mpc = mpc->next; } mpc_timer_refresh(); - - return; } static int atm_mpoa_ioctl(struct socket *sock, unsigned int cmd, @@ -1561,8 +1531,6 @@ static void __exit atm_mpoa_cleanup(void) kfree(qos); qos = nextqos; } - - return; } module_init(atm_mpoa_init); diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c index e773d833691..d1b2d9a0314 100644 --- a/net/atm/mpoa_caches.c +++ b/net/atm/mpoa_caches.c @@ -182,8 +182,6 @@ static void in_cache_put(in_cache_entry *entry) memset(entry, 0, sizeof(in_cache_entry)); kfree(entry); } - - return; } /* @@ -221,8 +219,6 @@ static void in_cache_remove_entry(in_cache_entry *entry, } vcc_release_async(vcc, -EPIPE); } - - return; } /* Call this every MPC-p2 seconds... Not exactly correct solution, @@ -248,8 +244,6 @@ static void clear_count_and_expired(struct mpoa_client *client) entry = next_entry; } write_unlock_bh(&client->ingress_lock); - - return; } /* Call this every MPC-p4 seconds. */ @@ -334,8 +328,6 @@ static void in_destroy_cache(struct mpoa_client *mpc) while (mpc->in_cache != NULL) mpc->in_ops->remove_entry(mpc->in_cache, mpc); write_unlock_irq(&mpc->ingress_lock); - - return; } static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, @@ -427,8 +419,6 @@ static void eg_cache_put(eg_cache_entry *entry) memset(entry, 0, sizeof(eg_cache_entry)); kfree(entry); } - - return; } /* @@ -463,8 +453,6 @@ static void eg_cache_remove_entry(eg_cache_entry *entry, } vcc_release_async(vcc, -EPIPE); } - - return; } static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, @@ -509,8 +497,6 @@ static void update_eg_cache_entry(eg_cache_entry *entry, uint16_t holding_time) do_gettimeofday(&(entry->tv)); entry->entry_state = EGRESS_RESOLVED; entry->ctrl_info.holding_time = holding_time; - - return; } static void clear_expired(struct mpoa_client *client) @@ -537,8 +523,6 @@ static void clear_expired(struct mpoa_client *client) entry = next_entry; } write_unlock_irq(&client->egress_lock); - - return; } static void eg_destroy_cache(struct mpoa_client *mpc) @@ -547,8 +531,6 @@ static void eg_destroy_cache(struct mpoa_client *mpc) while (mpc->eg_cache != NULL) mpc->eg_ops->remove_entry(mpc->eg_cache, mpc); write_unlock_irq(&mpc->egress_lock); - - return; } @@ -584,6 +566,4 @@ void atm_mpoa_init_cache(struct mpoa_client *mpc) { mpc->in_ops = &ingress_ops; mpc->eg_ops = &egress_ops; - - return; } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5e83f8e0877..2f768de8701 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1316,8 +1316,6 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) } tasklet_schedule(&hdev->tx_task); - - return; } EXPORT_SYMBOL(hci_send_acl); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 673a3688671..1b682a5aa06 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1322,8 +1322,6 @@ static void l2cap_drop_acked_frames(struct sock *sk) if (!l2cap_pi(sk)->unacked_frames) del_timer(&l2cap_pi(sk)->retrans_timer); - - return; } static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb) @@ -4667,7 +4665,6 @@ void l2cap_load(void) /* Dummy function to trigger automatic L2CAP module loading by * other modules that use L2CAP sockets but don't use any other * symbols from it. */ - return; } EXPORT_SYMBOL(l2cap_load); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index cab71ea2796..309b6c261b2 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -1014,8 +1014,6 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old) rfcomm_send_rpn(dev->dlc->session, 1, dev->dlc->dlci, baud, data_bits, stop_bits, parity, RFCOMM_RPN_FLOW_NONE, x_on, x_off, changes); - - return; } static void rfcomm_tty_throttle(struct tty_struct *tty) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 4767928a93d..d0927d1fdad 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -273,7 +273,6 @@ static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) drop: kfree_skb(skb); - return; } /* -------- Socket interface ---------- */ diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index 024fd5bb2d3..e2b86f1f5a4 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -112,7 +112,6 @@ static void caif_device_destroy(struct net_device *dev) spin_unlock_bh(&caifdevs->lock); kfree(caifd); - return; } static int transmit(struct cflayer *layer, struct cfpkt *pkt) diff --git a/net/can/bcm.c b/net/can/bcm.c index 907dc871fac..9c65e9deb9c 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -713,8 +713,6 @@ static void bcm_remove_op(struct bcm_op *op) kfree(op->last_frames); kfree(op); - - return; } static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op) diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 615dbe3b43f..4c409b46aa3 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -1220,17 +1220,14 @@ void dn_dev_down(struct net_device *dev) void dn_dev_init_pkt(struct sk_buff *skb) { - return; } void dn_dev_veri_pkt(struct sk_buff *skb) { - return; } void dn_dev_hello(struct sk_buff *skb) { - return; } void dn_dev_devices_off(void) diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index a8432e39954..812e6dff606 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -264,7 +264,6 @@ static struct dst_entry *dn_dst_negative_advice(struct dst_entry *dst) static void dn_dst_link_failure(struct sk_buff *skb) { - return; } static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index c97cd9ff697..3a92a76ae41 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -290,8 +290,6 @@ void cipso_v4_cache_invalidate(void) cipso_v4_cache[iter].size = 0; spin_unlock_bh(&cipso_v4_cache[iter].lock); } - - return; } /** diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index c98f115fb0f..79d057a939b 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1022,8 +1022,6 @@ static void trie_rebalance(struct trie *t, struct tnode *tn) rcu_assign_pointer(t->trie, (struct node *)tn); tnode_free_flush(); - - return; } /* only used from updater-side */ diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 498cf69c797..32618e11076 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -502,7 +502,6 @@ static void ipgre_err(struct sk_buff *skb, u32 info) t->err_time = jiffies; out: rcu_read_unlock(); - return; } static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 3244133c24f..ba9836c488e 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -238,7 +238,6 @@ void ip_options_fragment(struct sk_buff * skb) opt->rr_needaddr = 0; opt->ts_needaddr = 0; opt->ts_needtime = 0; - return; } /* diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 217ebe035b3..7bcacf627b4 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1606,7 +1606,6 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, out_free: kfree_skb(skb); - return; } static int ipmr_find_vif(struct mr_table *mrt, struct net_device *dev) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 3f7c12b70a2..0abdc242ddb 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -890,8 +890,6 @@ out: in6_ifa_put(ifp); else in6_dev_put(idev); - - return; } static void ndisc_recv_na(struct sk_buff *skb) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 458eabfbe13..566798d69f3 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -168,7 +168,6 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) i & 0x100 ? "Out" : "In", i & 0xff); seq_printf(seq, "%-32s\t%lu\n", name, val); } - return; } static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib, diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 05ebd783304..294cbe8b072 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -316,7 +316,6 @@ static void rt6_probe(struct rt6_info *rt) #else static inline void rt6_probe(struct rt6_info *rt) { - return; } #endif @@ -1553,7 +1552,6 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, out: dst_release(&rt->u.dst); - return; } /* diff --git a/net/irda/iriap.c b/net/irda/iriap.c index 79a1e5a23e1..fce364c6c71 100644 --- a/net/irda/iriap.c +++ b/net/irda/iriap.c @@ -685,8 +685,6 @@ static void iriap_getvaluebyclass_indication(struct iriap_cb *self, /* We have a match; send the value. */ iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS, attrib->value); - - return; } /* diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c index df18ab4b6c5..e98e40d76f4 100644 --- a/net/irda/irnet/irnet_irda.c +++ b/net/irda/irnet/irnet_irda.c @@ -678,7 +678,6 @@ irda_irnet_destroy(irnet_socket * self) self->stsap_sel = 0; DEXIT(IRDA_SOCK_TRACE, "\n"); - return; } @@ -928,7 +927,6 @@ irnet_disconnect_server(irnet_socket * self, irttp_listen(self->tsap); DEXIT(IRDA_SERV_TRACE, "\n"); - return; } /*------------------------------------------------------------------*/ @@ -1013,7 +1011,6 @@ irnet_destroy_server(void) irda_irnet_destroy(&irnet_server.s); DEXIT(IRDA_SERV_TRACE, "\n"); - return; } diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 8be324fe08b..c8b4599a752 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -136,7 +136,6 @@ static void afiucv_pm_complete(struct device *dev) #ifdef CONFIG_PM_DEBUG printk(KERN_WARNING "afiucv_pm_complete\n"); #endif - return; } /** diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h index 68e6a2050f9..09cc9be3479 100644 --- a/net/mac80211/debugfs.h +++ b/net/mac80211/debugfs.h @@ -7,7 +7,6 @@ extern int mac80211_open_file_generic(struct inode *inode, struct file *file); #else static inline void debugfs_hw_add(struct ieee80211_local *local) { - return; } #endif diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 7e93524459f..bde81031727 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -287,8 +287,6 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) *pos++ |= sdata->u.mesh.accepting_plinks ? MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; *pos++ = 0x00; - - return; } u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index d89ed7f2592..0705018d8d1 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -624,7 +624,6 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, fail: rcu_read_unlock(); sdata->u.mesh.mshstats.dropped_frames_no_route++; - return; } static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h index 07ae7fd82be..1c1c093cf27 100644 --- a/net/netlabel/netlabel_addrlist.h +++ b/net/netlabel/netlabel_addrlist.h @@ -130,7 +130,6 @@ static inline void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf, int src, const char *dev, __be32 addr, __be32 mask) { - return; } #endif @@ -203,7 +202,6 @@ static inline void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf, const struct in6_addr *addr, const struct in6_addr *mask) { - return; } #endif #endif /* IPV6 */ diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index a3d64aabe2f..e2b0a680dd5 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -670,7 +670,6 @@ static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface) unlhsh_condremove_failure: spin_unlock(&netlbl_unlhsh_lock); - return; } /** diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 6ed61b10e00..f73542d2cdd 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -602,7 +602,6 @@ static unsigned long flow_get(struct tcf_proto *tp, u32 handle) static void flow_put(struct tcf_proto *tp, unsigned long f) { - return; } static int flow_dump(struct tcf_proto *tp, unsigned long fh, diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index a435cf13cc2..abd904be428 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -617,7 +617,6 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y) rtsc->y = y; rtsc->dx = dx; rtsc->dy = dy; - return; } static void diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index a9e646bdb60..f10e34a6844 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -44,7 +44,6 @@ static void ingress_put(struct Qdisc *sch, unsigned long cl) static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker) { - return; } static struct tcf_proto **ingress_find_tcf(struct Qdisc *sch, unsigned long cl) diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index b2aba3f5e6f..fe91e50f9d9 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c @@ -174,7 +174,6 @@ static unsigned long mq_get(struct Qdisc *sch, u32 classid) static void mq_put(struct Qdisc *sch, unsigned long cl) { - return; } static int mq_dump_class(struct Qdisc *sch, unsigned long cl, diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index c50876cd870..6ae251279fc 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -340,7 +340,6 @@ static unsigned long multiq_bind(struct Qdisc *sch, unsigned long parent, static void multiq_put(struct Qdisc *q, unsigned long cl) { - return; } static int multiq_dump_class(struct Qdisc *sch, unsigned long cl, diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 81672e0c1b2..0748fb1e3a4 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -303,7 +303,6 @@ static unsigned long prio_bind(struct Qdisc *sch, unsigned long parent, u32 clas static void prio_put(struct Qdisc *q, unsigned long cl) { - return; } static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 072cdf442f8..8d42bb3ba54 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -303,7 +303,6 @@ static unsigned long red_get(struct Qdisc *sch, u32 classid) static void red_put(struct Qdisc *sch, unsigned long arg) { - return; } static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 3912420cedc..e41feff19e4 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -816,8 +816,6 @@ void sctp_assoc_del_nonprimary_peers(struct sctp_association *asoc, if (t != primary) sctp_assoc_rm_peer(asoc, t); } - - return; } /* Engage in transport control operations. diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 5d057178ce0..c04b2eb5918 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -80,7 +80,6 @@ static inline void sctp_outq_head_data(struct sctp_outq *q, { list_add(&ch->list, &q->out_chunk_list); q->out_qlen += ch->skb->len; - return; } /* Take data from the front of the queue. */ @@ -103,7 +102,6 @@ static inline void sctp_outq_tail_data(struct sctp_outq *q, { list_add_tail(&ch->list, &q->out_chunk_list); q->out_qlen += ch->skb->len; - return; } /* diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 784bcc9a979..61aacfbbaa9 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -181,7 +181,6 @@ static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) static void sctp_eps_seq_stop(struct seq_file *seq, void *v) { - return; } @@ -286,7 +285,6 @@ static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) static void sctp_assocs_seq_stop(struct seq_file *seq, void *v) { - return; } @@ -409,7 +407,6 @@ static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v) { - return; } static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 22e67020044..f5e5e27cac5 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -892,8 +892,6 @@ static void sctp_cmd_process_fwdtsn(struct sctp_ulpq *ulpq, sctp_walk_fwdtsn(skip, chunk) { sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn)); } - - return; } /* Helper function to remove the association non-primary peer @@ -912,8 +910,6 @@ static void sctp_cmd_del_non_primary(struct sctp_association *asoc) sctp_assoc_del_peer(asoc, &t->ipaddr); } } - - return; } /* Helper function to set sk_err on a 1-1 style socket. */ diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 3a448536f0b..c7f7e49609c 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -955,7 +955,6 @@ void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn) * ordering and deliver them if needed. */ sctp_ulpq_reap_ordered(ulpq, sid); - return; } static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq, @@ -1064,7 +1063,6 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, } sk_mem_reclaim(asoc->base.sk); - return; } diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 19c9983d536..462462eaf29 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1518,7 +1518,6 @@ call_refreshresult(struct rpc_task *task) task->tk_action = call_refresh; if (status != -ETIMEDOUT) rpc_delay(task, 3*HZ); - return; } static __be32 * diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index ce0d5b35c2a..76e504bf74d 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -150,7 +150,6 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) } break; } - return; } /* diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 699ade68aac..2e3d502ffe8 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -716,7 +716,6 @@ void xprt_connect(struct rpc_task *task) xprt->stat.connect_start = jiffies; xprt->ops->connect(task); } - return; } static void xprt_connect_status(struct rpc_task *task) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 9847c30b500..6e0df664b25 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1050,8 +1050,6 @@ static inline void xs_tcp_read_common(struct rpc_xprt *xprt, if (transport->tcp_flags & TCP_RCV_LAST_FRAG) transport->tcp_flags &= ~TCP_RCV_COPY_DATA; } - - return; } /* @@ -2210,7 +2208,6 @@ static int bc_send_request(struct rpc_task *task) static void bc_close(struct rpc_xprt *xprt) { - return; } /* @@ -2220,7 +2217,6 @@ static void bc_close(struct rpc_xprt *xprt) static void bc_destroy(struct rpc_xprt *xprt) { - return; } static struct rpc_xprt_ops xs_udp_ops = { diff --git a/net/sysctl_net.c b/net/sysctl_net.c index 53196009160..ca84212cfbf 100644 --- a/net/sysctl_net.c +++ b/net/sysctl_net.c @@ -82,7 +82,6 @@ static int __net_init sysctl_net_init(struct net *net) static void __net_exit sysctl_net_exit(struct net *net) { WARN_ON(!list_empty(&net->sysctls.list)); - return; } static struct pernet_operations sysctl_pernet_ops = { diff --git a/net/wimax/stack.c b/net/wimax/stack.c index 62b1a666220..ee99e7dfcdb 100644 --- a/net/wimax/stack.c +++ b/net/wimax/stack.c @@ -320,7 +320,6 @@ void __wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state) out: d_fnend(3, dev, "(wimax_dev %p new_state %u [old %u]) = void\n", wimax_dev, new_state, old_state); - return; } @@ -362,7 +361,6 @@ void wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state) if (wimax_dev->state > __WIMAX_ST_NULL) __wimax_state_change(wimax_dev, new_state); mutex_unlock(&wimax_dev->mutex); - return; } EXPORT_SYMBOL_GPL(wimax_state_change); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index f4ea3a08e5a..d965a2bad8d 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2209,7 +2209,6 @@ EXPORT_SYMBOL(xfrm_dst_ifdown); static void xfrm_link_failure(struct sk_buff *skb) { /* Impossible. Such dst must be popped before reaches point of failure. */ - return; } static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) -- cgit v1.2.3-70-g09d2