Skip to contentSkip to conversation

Pull request: bluetooth-next-2.6 2010-05-10

PATCH New Marcel Holtmann 2 participants 72 messages May 10, 2010

Subsystems (4)
lore
Share & tools
lore

Marcel Holtmann

author maintainer
#0 lore raw

Hi Dave,

this is the big merge for the L2CAP Enhanced Retransmission support work done by Gustavo F. Padovan. All other changes are small cleanups.

Regards

Marcel

Please pull from

git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluetooth-next-2.6.git master

This will update the following files:

 drivers/bluetooth/btmrvl_drv.h   |    8 +-
 drivers/bluetooth/btmrvl_main.c  |   92 ++--
 drivers/bluetooth/btmrvl_sdio.c  |    7 +-
 drivers/bluetooth/hci_h4.c       |    2 +-
 drivers/bluetooth/hci_ll.c       |    8 +-
 drivers/bluetooth/hci_vhci.c     |    2 +-
 include/net/bluetooth/hci_core.h |    6 +-
 include/net/bluetooth/l2cap.h    |   41 +-
 net/bluetooth/Kconfig            |   13 +
 net/bluetooth/hci_core.c         |   27 +-
 net/bluetooth/hci_sysfs.c        |   34 +-
 net/bluetooth/l2cap.c            | 1108 +++++++++++++++++++++++++++++---------
 net/bluetooth/sco.c              |   26 +-
 13 files changed, 1010 insertions(+), 364 deletions(-)

through these ChangeSets:

Bing Zhao (3):
Bluetooth: Decode btmrvl MODULE_BRINGUP_REG response correctly
Bluetooth: Separate btmrvl_register_hdev() from btmrvl_add_card()
Bluetooth: Set hdev->dev_type based on Marvell device type

Dan Carpenter (1):
Bluetooth: Fix storing negative values as unsigned char

Gustavo F. Padovan (54):
Bluetooth: Fix return value when bt_skb_alloc fails
Bluetooth: Use the proper function cast to get hdr data
Bluetooth: Fix wrong packet type count increment
Bluetooth: Make hci_send_sco() void
Bluetooth: Trivial clean ups to SCO
Bluetooth: Move specific Basic Mode code to the right place
Bluetooth: Fix memory leak of S-frames into L2CAP
Bluetooth: Fix expected_tx_seq calculation on L2CAP
Bluetooth: Fix ACL MTU issue
Bluetooth: Use a l2cap_pinfo struct instead l2cap_pi() macro
Bluetooth: Implement 'Send IorRRorRNR' event
Bluetooth: Support case with F bit set under WAIT_F state.
Bluetooth: Check the minimum {I,S}-frame size into L2CAP
Bluetooth: Check if SDU size is greater than MTU on L2CAP
Bluetooth: Implement SendAck() Action on ERTM.
Bluetooth: Move set of P-bit to l2cap_send_sframe()
Bluetooth: Add Recv RR (P=0)(F=0) for SREJ_SENT state on ERTM
Bluetooth: Split l2cap_data_channel_sframe()
Bluetooth: Handle all cases of receipt of RNR-frames into L2CAP
Bluetooth: Group the ack of I-frames into l2cap_data_channel_rrframe()
Bluetooth: Remove duplicate use of __get_reqseq() macro on L2CAP
Bluetooth: Finish implementation for Rec RR (P=1) on ERTM
Bluetooth: Add timer to Acknowledge I-frames
Bluetooth: Ignore Tx Window value with Streaming mode
Bluetooth: Read RFC conf option on a successful Conf RSP
Bluetooth: Fix configuration of the MPS value
Bluetooth: Add le16 macro to Retransmission and Monitor Timeouts values
Bluetooth: Check the SDU size against the MTU value
Bluetooth: Send Ack after clear the SREJ list
Bluetooth: Add sockopt configuration for txWindow on L2CAP
Bluetooth: Change acknowledgement to use the value of txWindow
Bluetooth: Add module parameter for txWindow size on L2CAP
Bluetooth: Enable option to configure Max Transmission value via
Bluetooth: Fix bug when retransmitting I-frames
Bluetooth: Fix crash when monitor timeout expires
Bluetooth: Fix drop of acked packets on ERTM
Bluetooth: Optimize SREJ_QUEUE append
Bluetooth: Add Kconfig option for L2CAP Extended Features
Bluetooth: Add SOCK_STREAM support to L2CAP
Bluetooth: Fix SDU reassembly under SREJ
Bluetooth: Don't set control bits to zero first
Bluetooth: Fix errors reported by checkpatch.pl
Bluetooth: Remove set of SrejSaveReqSeq under receipt of REJ frame
Bluetooth: Remove unneeded control vars
Bluetooth: Check if we really are in WAIT_F when F bit comes
Bluetooth: Fix lockdep annotation on ERTM
Bluetooth: Make hci_send_acl() void
Bluetooth: Refactor l2cap_retransmit_frame()
Bluetooth: Implement missing parts of the Invalid Frame Detection
Bluetooth: Implement Local Busy Condition handling
Bluetooth: Add wait_queue to wait ack of all sent packets
Bluetooth: Fix race condition on l2cap_ertm_send()
Bluetooth: Prevents buffer overflow on l2cap_ertm_reassembly_sdu()
Bluetooth: Fix spec error in the RemoteBusy Logic

João Paulo Rechi Vita (3):
Bluetooth: Check if mode is supported on getsockopt
Bluetooth: Close L2CAP channel on invalid ReqSeq
Bluetooth: Completes the I-frame tx_seq check logic on RECV

Marcel Holtmann (2):
Bluetooth: Create per controller workqueue
Bluetooth: Fix issues where sk_sleep() helper is needed now

Tomas Winkler (1):
Bluetooth: Use strict_strtoul instead of simple_strtoul

author maintainer
#1 lore raw

PATCH 1/64 Bluetooth: Fix return value when bt_skb_alloc fails

From: Gustavo F. Padovan <[email protected]>

Set the proper error(ENOMEM), instead of just return 0.

---
 drivers/bluetooth/hci_h4.c |    2 +-
 drivers/bluetooth/hci_ll.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/bluetooth/hci_h4.c +1 -1
index c0ce813..3f038f5 100644
@@ -246,7 +246,7 @@ static int h4_recv(struct hci_uart *hu, void *data, int count)
 			BT_ERR("Can't allocate mem for new packet");
 			h4->rx_state = H4_W4_PACKET_TYPE;
 			h4->rx_count = 0;
-			return 0;
+			return -ENOMEM;
 		}
 
 		h4->rx_skb->dev = (void *) hu->hdev;
drivers/bluetooth/hci_ll.c +1 -1
index 5c65014..91e44df 100644
@@ -491,7 +491,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
 			BT_ERR("Can't allocate mem for new packet");
 			ll->rx_state = HCILL_W4_PACKET_TYPE;
 			ll->rx_count = 0;
-			return 0;
+			return -ENOMEM;
 		}
 
 		ll->rx_skb->dev = (void *) hu->hdev;
Signature · 1 line
1.6.6.1
author maintainer
#2 lore raw

PATCH 2/64 Bluetooth: Use the proper function cast to get hdr data

From: Gustavo F. Padovan <[email protected]>

---
 drivers/bluetooth/hci_ll.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
drivers/bluetooth/hci_ll.c +3 -3
index 91e44df..fb8445c 100644
@@ -402,7 +402,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
 				continue;
 
 			case HCILL_W4_EVENT_HDR:
-				eh = (struct hci_event_hdr *) ll->rx_skb->data;
+				eh = hci_event_hdr(ll->rx_skb);
 
 				BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
 
@@ -410,7 +410,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
 				continue;
 
 			case HCILL_W4_ACL_HDR:
-				ah = (struct hci_acl_hdr *) ll->rx_skb->data;
+				ah = hci_acl_hdr(ll->rx_skb);
 				dlen = __le16_to_cpu(ah->dlen);
 
 				BT_DBG("ACL header: dlen %d", dlen);
@@ -419,7 +419,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
 				continue;
 
 			case HCILL_W4_SCO_HDR:
-				sh = (struct hci_sco_hdr *) ll->rx_skb->data;
+				sh = hci_sco_hdr(ll->rx_skb);
 
 				BT_DBG("SCO header: dlen %d", sh->dlen);
 
Signature · 1 line
1.6.6.1
author maintainer
#3 lore raw

PATCH 3/64 Bluetooth: Fix wrong packet type count increment

From: Gustavo F. Padovan <[email protected]>

---
 drivers/bluetooth/hci_vhci.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/bluetooth/hci_vhci.c +1 -1
index bb0aefd..3aa7b2a 100644
@@ -157,7 +157,7 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
 		break;
 
 	case HCI_SCODATA_PKT:
-		data->hdev->stat.cmd_tx++;
+		data->hdev->stat.sco_tx++;
 		break;
 	};
 
Signature · 1 line
1.6.6.1
author maintainer
#4 lore raw

PATCH 4/64 Bluetooth: Make hci_send_sco() void

From: Gustavo F. Padovan <[email protected]>

It also removes an unneeded check for the MTU. The check is done before on sco_send_frame()

---
 include/net/bluetooth/hci_core.h |    2 +-
 net/bluetooth/hci_core.c         |    9 +--------
 net/bluetooth/sco.c              |    3 +--
 3 files changed, 3 insertions(+), 11 deletions(-)
include/net/bluetooth/hci_core.h +1 -1
index ce3c99e..9830a88 100644
@@ -637,7 +637,7 @@ 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);
-int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
+void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
 
net/bluetooth/hci_core.c +1 -8
index 4ad2319..1c9aef9 100644
@@ -1308,18 +1308,13 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 EXPORT_SYMBOL(hci_send_acl);
 
 /* Send SCO data */
-int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
+void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
 {
 	struct hci_dev *hdev = conn->hdev;
 	struct hci_sco_hdr hdr;
 
 	BT_DBG("%s len %d", hdev->name, skb->len);
 
-	if (skb->len > hdev->sco_mtu) {
-		kfree_skb(skb);
-		return -EINVAL;
-	}
-
 	hdr.handle = cpu_to_le16(conn->handle);
 	hdr.dlen   = skb->len;
 
@@ -1332,8 +1327,6 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
 
 	skb_queue_tail(&conn->data_q, skb);
 	tasklet_schedule(&hdev->tx_task);
-
-	return 0;
 }
 EXPORT_SYMBOL(hci_send_sco);
 
net/bluetooth/sco.c +1 -2
index b406d3e..541b26e 100644
@@ -249,8 +249,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
 		goto fail;
 	}
 
-	if ((err = hci_send_sco(conn->hcon, skb)) < 0)
-		return err;
+	hci_send_sco(conn->hcon, skb);
 
 	return count;
 
Signature · 1 line
1.6.6.1
author maintainer
#5 lore raw

PATCH 5/64 Bluetooth: Trivial clean ups to SCO

From: Gustavo F. Padovan <[email protected]>

Remove extra braces and labels, break over column 80 lines, etc

---
 net/bluetooth/sco.c |   23 +++++++++++------------
 1 files changed, 11 insertions(+), 12 deletions(-)
net/bluetooth/sco.c +11 -12
index 541b26e..4767928 100644
@@ -165,11 +165,11 @@ static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct so
 	int err = 0;
 
 	sco_conn_lock(conn);
-	if (conn->sk) {
+	if (conn->sk)
 		err = -EBUSY;
-	} else {
+	else
 		__sco_chan_add(conn, sk, parent);
-	}
+
 	sco_conn_unlock(conn);
 	return err;
 }
@@ -241,21 +241,19 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
 	BT_DBG("sk %p len %d", sk, len);
 
 	count = min_t(unsigned int, conn->mtu, len);
-	if (!(skb = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
+	skb = bt_skb_send_alloc(sk, count,
+			msg->msg_flags & MSG_DONTWAIT, &err);
+	if (!skb)
 		return err;
 
 	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-		err = -EFAULT;
-		goto fail;
+		kfree_skb(skb);
+		return -EFAULT;
 	}
 
 	hci_send_sco(conn->hcon, skb);
 
 	return count;
-
-fail:
-	kfree_skb(skb);
-	return err;
 }
 
 static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
@@ -625,7 +623,7 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 			    struct msghdr *msg, size_t len)
 {
 	struct sock *sk = sock->sk;
-	int err = 0;
+	int err;
 
 	BT_DBG("sock %p, sk %p", sock, sk);
 
@@ -850,7 +848,8 @@ static void sco_conn_ready(struct sco_conn *conn)
 
 		bh_lock_sock(parent);
 
-		sk = sco_sock_alloc(sock_net(parent), NULL, BTPROTO_SCO, GFP_ATOMIC);
+		sk = sco_sock_alloc(sock_net(parent), NULL,
+				BTPROTO_SCO, GFP_ATOMIC);
 		if (!sk) {
 			bh_unlock_sock(parent);
 			goto done;
Signature · 1 line
1.6.6.1
author maintainer
#6 lore raw

PATCH 6/64 Bluetooth: Move specific Basic Mode code to the right place

From: Gustavo F. Padovan <[email protected]>

Inside "case L2CAP_MODE_BASIC:" we don't need to check for sk_type and L2CAP mode. So only the length check is fine.

---
 net/bluetooth/l2cap.c |   11 ++++++-----
 1 files changed, 6 insertions(+), 5 deletions(-)
net/bluetooth/l2cap.c +6 -5
index 864c76f..c9a848d 100644
@@ -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)) {
Signature · 1 line
1.6.6.1
author maintainer
#7 lore raw

PATCH 7/64 Bluetooth: Fix memory leak of S-frames into L2CAP

From: Gustavo F. Padovan <[email protected]>

l2cap_data_channel do not free the S-frame, so we free it here.

---
 net/bluetooth/l2cap.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
net/bluetooth/l2cap.c +1 -0
index c9a848d..46f2264 100644
@@ -3522,6 +3522,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
 		break;
 	}
 
+	kfree_skb(skb);
 	return 0;
 }
 
Signature · 1 line
1.6.6.1
author maintainer
#8 lore raw

PATCH 8/64 Bluetooth: Fix expected_tx_seq calculation on L2CAP

From: Gustavo F. Padovan <[email protected]>

All operation related to the txWindow should be modulo 64.

---
 net/bluetooth/l2cap.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +1 -1
index 46f2264..401011a 100644
@@ -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);
 
Signature · 1 line
1.6.6.1
author maintainer
#9 lore raw

PATCH 9/64 Bluetooth: Fix ACL MTU issue

From: Gustavo F. Padovan <[email protected]>

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.

---
 net/bluetooth/l2cap.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)
net/bluetooth/l2cap.c +4 -0
index 401011a..99cf177 100644
@@ -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);
Signature · 1 line
1.6.6.1
author maintainer
#10 lore raw

PATCH 10/64 Bluetooth: Use a l2cap_pinfo struct instead l2cap_pi() macro

From: Gustavo F. Padovan <[email protected]>

Trivial clean up.

---
 net/bluetooth/l2cap.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)
net/bluetooth/l2cap.c +6 -6
index 99cf177..a9c152a 100644
@@ -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;
 	}
 
Signature · 1 line
1.6.6.1
author maintainer
#11 lore raw

PATCH 11/64 Bluetooth: Implement 'Send IorRRorRNR' event

From: Gustavo F. Padovan <[email protected]>

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.

---
 include/net/bluetooth/l2cap.h |   20 ++++++++++--------
 net/bluetooth/l2cap.c         |   43 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 50 insertions(+), 13 deletions(-)
include/net/bluetooth/l2cap.h +11 -9
index 17a689f..d9c20c3 100644
@@ -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));
net/bluetooth/l2cap.c +39 -4

73 lines not on this page · raw message

Signature · 1 line
1.6.6.1
author maintainer
#12 lore raw

PATCH 12/64 Bluetooth: Support case with F bit set under WAIT_F state.

From: Gustavo F. Padovan <[email protected]>

On receipt of a F=1 under WAIT_F state ERTM shall stop monitor timer and start retransmission timer (if there are unacked frames).

---
 net/bluetooth/l2cap.c |   22 ++++++++++++++--------
 1 files changed, 14 insertions(+), 8 deletions(-)
net/bluetooth/l2cap.c +14 -8
index 06687e2..36cd4e4 100644
@@ -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);
Signature · 1 line
1.6.6.1
author maintainer
#13 lore raw

PATCH 13/64 Bluetooth: Check the minimum {I,S}-frame size into L2CAP

From: Gustavo F. Padovan <[email protected]>

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.

---
 net/bluetooth/l2cap.c |   14 +++++++++++---
 1 files changed, 11 insertions(+), 3 deletions(-)
net/bluetooth/l2cap.c +11 -3
index 36cd4e4..ac00f5f 100644
@@ -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))
Signature · 1 line
1.6.6.1
author maintainer
#14 lore raw

PATCH 14/64 Bluetooth: Check if SDU size is greater than MTU on L2CAP

From: Gustavo F. Padovan <[email protected]>

After reassembly the SDU we need to check his size. It can't overflow the MTU size.

---
 net/bluetooth/l2cap.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +5 -1
index ac00f5f..2e354d2 100644
@@ -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;
 	}
 
Signature · 1 line
1.6.6.1
author maintainer
#15 lore raw

PATCH 15/64 Bluetooth: Implement SendAck() Action on ERTM.

From: Gustavo F. Padovan <[email protected]>

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.

---
 net/bluetooth/l2cap.c |   41 +++++++++++++++++++++++++++++------------
 1 files changed, 29 insertions(+), 12 deletions(-)
net/bluetooth/l2cap.c +29 -12
index 2e354d2..0a739ef 100644
@@ -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;
 }
 
Signature · 1 line
1.6.6.1
author maintainer
#16 lore raw

PATCH 16/64 Bluetooth: Move set of P-bit to l2cap_send_sframe()

From: Gustavo F. Padovan <[email protected]>

Abstract the send of of P-bit and avoids code duplication like we did with the setting of F-bit.

---
 net/bluetooth/l2cap.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
net/bluetooth/l2cap.c +5 -4
index 0a739ef..852c140 100644
@@ -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);
Signature · 1 line
1.6.6.1
author maintainer
#17 lore raw

PATCH 17/64 Bluetooth: Add Recv RR (P=0)(F=0) for SREJ_SENT state on ERTM

From: Gustavo F. Padovan <[email protected]>

This finishes the implementation of Recv RR (P=0)(F=0) for the Enhanced Retransmission Mode on L2CAP.

---
 net/bluetooth/l2cap.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +4 -1
index 852c140..e5cd64a 100644
@@ -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;
 
Signature · 1 line
1.6.6.1
author maintainer
#18 lore raw

PATCH 18/64 Bluetooth: Split l2cap_data_channel_sframe()

From: Gustavo F. Padovan <[email protected]>

Create a function for each type fo S-frame and avoid a lot of nested code.

---
 net/bluetooth/l2cap.c |  204 +++++++++++++++++++++++++++---------------------
 1 files changed, 115 insertions(+), 89 deletions(-)
net/bluetooth/l2cap.c +115 -89
index e5cd64a..068edf7 100644
@@ -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;
 	}
 
Signature · 1 line
1.6.6.1
author maintainer
#19 lore raw

PATCH 19/64 Bluetooth: Handle all cases of receipt of RNR-frames into L2CAP

From: Gustavo F. Padovan <[email protected]>

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.

---
 net/bluetooth/l2cap.c |   32 ++++++++++++++++++++++++++++----
 1 files changed, 28 insertions(+), 4 deletions(-)
net/bluetooth/l2cap.c +28 -4
index 068edf7..8937a84 100644
@@ -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)
Signature · 1 line
1.6.6.1
author maintainer
#20 lore raw

PATCH 20/64 Bluetooth: Group the ack of I-frames into l2cap_data_channel_rrframe()

From: Gustavo F. Padovan <[email protected]>

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.

---
 net/bluetooth/l2cap.c |    9 +++------
 1 files changed, 3 insertions(+), 6 deletions(-)
net/bluetooth/l2cap.c +3 -6
index 8937a84..d096c7c 100644
@@ -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();
Signature · 1 line
1.6.6.1
author maintainer
#21 lore raw

PATCH 21/64 Bluetooth: Remove duplicate use of __get_reqseq() macro on L2CAP

From: Gustavo F. Padovan <[email protected]>

tx_seq var already has the value of __get_reqseq().

---
 net/bluetooth/l2cap.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +1 -1
index d096c7c..e9ac9fb 100644
@@ -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) {
Signature · 1 line
1.6.6.1
author maintainer
#22 lore raw

PATCH 22/64 Bluetooth: Finish implementation for Rec RR (P=1) on ERTM

From: Gustavo F. Padovan <[email protected]>

Now the code handles the case under SREJ_SENT state.

---
 net/bluetooth/l2cap.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)
net/bluetooth/l2cap.c +11 -2
index e9ac9fb..f386985 100644
@@ -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;
Signature · 1 line
1.6.6.1
author maintainer
#23 lore raw

PATCH 23/64 Bluetooth: Add timer to Acknowledge I-frames

From: Gustavo F. Padovan <[email protected]>

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.

---
 include/net/bluetooth/l2cap.h |    4 ++++
 net/bluetooth/l2cap.c         |   15 +++++++++++++++
 2 files changed, 19 insertions(+), 0 deletions(-)
include/net/bluetooth/l2cap.h +4 -0
index d9c20c3..48f10f4 100644
@@ -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)
 {
net/bluetooth/l2cap.c +15 -0
index f386985..0300656 100644
@@ -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);
Signature · 1 line
1.6.6.1
author maintainer
#24 lore raw

PATCH 24/64 Bluetooth: Ignore Tx Window value with Streaming mode

From: Gustavo F. Padovan <[email protected]>

Tx Window value shall not be used with Streaming Mode and the receiver of the config Request shall ignore its value.

---
 net/bluetooth/l2cap.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +0 -1
index 0300656..f604405 100644
@@ -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;
Signature · 1 line
1.6.6.1
author maintainer
#25 lore raw

PATCH 25/64 Bluetooth: Read RFC conf option on a successful Conf RSP

From: Gustavo F. Padovan <[email protected]>

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.

---
 net/bluetooth/l2cap.c |   39 ++++++++++++++++++++++++++++++++++++++-
 1 files changed, 38 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +38 -1
index f604405..c50c057 100644
@@ -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)) {
Signature · 1 line
1.6.6.1
author maintainer
#26 lore raw

PATCH 26/64 Bluetooth: Fix configuration of the MPS value

From: Gustavo F. Padovan <[email protected]>

We were accepting values bigger than we can accept. This was leading ERTM to drop packets because of wrong FCS checks.

---
 include/net/bluetooth/l2cap.h |    3 ++-
 net/bluetooth/l2cap.c         |   36 ++++++++++++++++++++----------------
 2 files changed, 22 insertions(+), 17 deletions(-)
include/net/bluetooth/l2cap.h +2 -1
index 48f10f4..0f4e423 100644
@@ -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;
 
net/bluetooth/l2cap.c +20 -16
index c50c057..94be5db 100644
@@ -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))
Signature · 1 line
1.6.6.1
author maintainer
#27 lore raw

PATCH 27/64 Bluetooth: Add le16 macro to Retransmission and Monitor Timeouts values

From: Gustavo F. Padovan <[email protected]>

Fix a possible problem with Big Endian machines.

---
 net/bluetooth/l2cap.c |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)
net/bluetooth/l2cap.c +8 -6
index 94be5db..0889949 100644
@@ -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:
Signature · 1 line
1.6.6.1
author maintainer
#28 lore raw

PATCH 28/64 Bluetooth: Check the SDU size against the MTU value

From: Gustavo F. Padovan <[email protected]>

If the SDU size is greater than the MTU something is wrong, so report an error.

---
 net/bluetooth/l2cap.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
net/bluetooth/l2cap.c +5 -0
index 0889949..e936913 100644
@@ -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;
Signature · 1 line
1.6.6.1
author maintainer
#29 lore raw

PATCH 29/64 Bluetooth: Send Ack after clear the SREJ list

From: Gustavo F. Padovan <[email protected]>

As specified by Bluetooth 3.0 spec we shall send an acknowledgment using the Send-Ack() after clear the SREJ list.

---
 net/bluetooth/l2cap.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
net/bluetooth/l2cap.c +1 -0
index e936913..c6bc1b9 100644
@@ -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;
Signature · 1 line
1.6.6.1
author maintainer
#30 lore raw

PATCH 30/64 Bluetooth: Add sockopt configuration for txWindow on L2CAP

From: Gustavo F. Padovan <[email protected]>

Now we can set/get Transmission Window size via sockopt.

---
 include/net/bluetooth/l2cap.h |    2 ++
 net/bluetooth/l2cap.c         |    7 ++++++-
 2 files changed, 8 insertions(+), 1 deletions(-)
include/net/bluetooth/l2cap.h +2 -0
index 0f4e423..07ae4cc 100644
@@ -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;
net/bluetooth/l2cap.c +6 -1
index c6bc1b9..5300796 100644
@@ -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;
Signature · 1 line
1.6.6.1
author maintainer
#31 lore raw

PATCH 31/64 Bluetooth: Change acknowledgement to use the value of txWindow

From: Gustavo F. Padovan <[email protected]>

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.

---
 include/net/bluetooth/l2cap.h |    3 +--
 net/bluetooth/l2cap.c         |    7 ++++---
 2 files changed, 5 insertions(+), 5 deletions(-)
include/net/bluetooth/l2cap.h +1 -2
index 07ae4cc..059260b 100644
@@ -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;
net/bluetooth/l2cap.c +4 -3
index 5300796..0b0b237 100644
@@ -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;
Signature · 1 line
1.6.6.1
author maintainer
#32 lore raw

PATCH 32/64 Bluetooth: Add module parameter for txWindow size on L2CAP

From: Gustavo F. Padovan <[email protected]>

Very useful for testing purposes.

---
 net/bluetooth/l2cap.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +5 -1
index 0b0b237..ff1466b 100644
@@ -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 <[email protected]>");
 MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
 MODULE_VERSION(VERSION);
Signature · 1 line
1.6.6.1
author maintainer
#33 lore raw

PATCH 33/64 Bluetooth: Enable option to configure Max Transmission value via sockopt

From: Gustavo F. Padovan <[email protected]>

With the sockopt extension we can set a per-channel MaxTx value.

---
 include/net/bluetooth/l2cap.h |    2 ++
 net/bluetooth/l2cap.c         |    7 ++++++-
 2 files changed, 8 insertions(+), 1 deletions(-)
include/net/bluetooth/l2cap.h +2 -0
index 059260b..8942c2f 100644
@@ -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;
net/bluetooth/l2cap.c +6 -1
index ff1466b..f9e4da2 100644
@@ -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);
Signature · 1 line
1.6.6.1
author maintainer
#34 lore raw

PATCH 34/64 Bluetooth: Fix bug when retransmitting I-frames

From: Gustavo F. Padovan <[email protected]>

If there is no frames to retransmit l2cap was crashing the kernel, now we check if the queue is empty first.

---
 net/bluetooth/l2cap.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)
net/bluetooth/l2cap.c +8 -4
index f9e4da2..4c7b2d2 100644
@@ -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);
 
Signature · 1 line
1.6.6.1
author maintainer
#35 lore raw

PATCH 35/64 Bluetooth: Fix crash when monitor timeout expires

From: Gustavo F. Padovan <[email protected]>

The code was crashing due to a invalid access to hci_conn after the channel disconnect.

---
 net/bluetooth/l2cap.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
net/bluetooth/l2cap.c +3 -0
index 4c7b2d2..2f9bbad 100644
@@ -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;
 
Signature · 1 line
1.6.6.1
author maintainer
#36 lore raw

PATCH 36/64 Bluetooth: Fix drop of acked packets on ERTM

From: Gustavo F. Padovan <[email protected]>

l2cap_drop_acked_frames() was droping not sent packets, causing them to be not transmitted.

---
 net/bluetooth/l2cap.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +2 -1
index 2f9bbad..042fd96 100644
@@ -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;
 
Signature · 1 line
1.6.6.1
author maintainer
#37 lore raw

PATCH 37/64 Bluetooth: Optimize SREJ_QUEUE append

From: Gustavo F. Padovan <[email protected]>

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).

---
 net/bluetooth/l2cap.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +3 -1
index 042fd96..187f46d 100644
@@ -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;
 	}
 
Signature · 1 line
1.6.6.1
author maintainer
#38 lore raw

PATCH 38/64 Bluetooth: Add Kconfig option for L2CAP Extended Features

From: Gustavo F. Padovan <[email protected]>

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).

---
 net/bluetooth/Kconfig |   13 +++++++++++++
 net/bluetooth/l2cap.c |    4 ++++
 2 files changed, 17 insertions(+), 0 deletions(-)
net/bluetooth/Kconfig +13 -0
index ed37168..ee3b304 100644
@@ -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
net/bluetooth/l2cap.c +4 -0
index 187f46d..4c00720 100644
@@ -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;
 
Signature · 1 line
1.6.6.1
author maintainer
#39 lore raw

PATCH 39/64 Bluetooth: Add SOCK_STREAM support to L2CAP

From: Gustavo F. Padovan <[email protected]>

if enable_ertm is true and we have SOCK_STREAM the default mode will be ERTM, otherwise Basic Mode.

---
 net/bluetooth/l2cap.c |   40 ++++++++++++++++++++++++++--------------
 1 files changed, 26 insertions(+), 14 deletions(-)
net/bluetooth/l2cap.c +26 -14
index 4c00720..1a32562 100644
@@ -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) {
Signature · 1 line
1.6.6.1
author maintainer
#40 lore raw

PATCH 40/64 Bluetooth: Check if mode is supported on getsockopt

From: João Paulo Rechi Vita <[email protected]>

Add this check to getsockopt makes possible to fail early instead of waiting until listen / connect.

---
 net/bluetooth/l2cap.c |   15 ++++++++++++++-
 1 files changed, 14 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +14 -1
index 1a32562..bf5bb7d 100644
@@ -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;
Signature · 1 line
1.6.6.1
author maintainer
#41 lore raw

PATCH 41/64 Bluetooth: Fix SDU reassembly under SREJ

From: Gustavo F. Padovan <[email protected]>

The code was reusing the control var without its reinitialization.

---
 net/bluetooth/l2cap.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
net/bluetooth/l2cap.c +2 -2
index bf5bb7d..478def7 100644
@@ -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;
Signature · 1 line
1.6.6.1
author maintainer
#42 lore raw

PATCH 42/64 Bluetooth: Close L2CAP channel on invalid ReqSeq

From: João Paulo Rechi Vita <[email protected]>

---
 net/bluetooth/l2cap.c |   18 +++++++++++++++++-
 1 files changed, 17 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +17 -1
index 478def7..31514d8 100644
@@ -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;
Signature · 1 line
1.6.6.1
author maintainer
#43 lore raw

PATCH 43/64 Bluetooth: Don't set control bits to zero first

From: Gustavo F. Padovan <[email protected]>

We can set the SAR bits in the control field directly.

---
 net/bluetooth/l2cap.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)
net/bluetooth/l2cap.c +2 -4
index 31514d8..cfb18cd 100644
@@ -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)
Signature · 1 line
1.6.6.1
author maintainer
#44 lore raw

PATCH 44/64 Bluetooth: Fix errors reported by checkpatch.pl

From: Gustavo F. Padovan <[email protected]>

---
 net/bluetooth/l2cap.c |   11 +++++------
 1 files changed, 5 insertions(+), 6 deletions(-)
net/bluetooth/l2cap.c +5 -6
index cfb18cd..2a981de 100644
@@ -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);
Signature · 1 line
1.6.6.1
author maintainer
#45 lore raw

PATCH 45/64 Bluetooth: Remove set of SrejSaveReqSeq under receipt of REJ frame

From: Gustavo F. Padovan <[email protected]>

That action is not specified by the ERTM spec, so removing it.

---
 net/bluetooth/l2cap.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)
net/bluetooth/l2cap.c +1 -3
index 2a981de..d0d0330 100644
@@ -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)
Signature · 1 line
1.6.6.1
author maintainer
#46 lore raw

PATCH 46/64 Bluetooth: Remove unneeded control vars

From: Gustavo F. Padovan <[email protected]>

Trivial clean up.

---
 net/bluetooth/l2cap.c |   14 ++++----------
 1 files changed, 4 insertions(+), 10 deletions(-)
net/bluetooth/l2cap.c +4 -10
index d0d0330..5a5203f 100644
@@ -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;
 	}
 
Signature · 1 line
1.6.6.1
author maintainer
#47 lore raw

PATCH 47/64 Bluetooth: Check if we really are in WAIT_F when F bit comes

From: Gustavo F. Padovan <[email protected]>

F-bit set should be processed only if we are in the WAIT_F state.

---
 net/bluetooth/l2cap.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
net/bluetooth/l2cap.c +4 -2
index 5a5203f..eb5cb29 100644
@@ -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();
Signature · 1 line
1.6.6.1
author maintainer
#48 lore raw

PATCH 48/64 Bluetooth: Fix lockdep annotation on ERTM

From: Gustavo F. Padovan <[email protected]>

A spin_lock_init() call was missing. :)

---
 net/bluetooth/l2cap.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +1 -1
index eb5cb29..6b08f4d 100644
@@ -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))
Signature · 1 line
1.6.6.1
author maintainer
#49 lore raw

PATCH 49/64 Bluetooth: Make hci_send_acl() void

From: Gustavo F. Padovan <[email protected]>

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.

---
 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(-)
include/net/bluetooth/hci_core.h +1 -1
index 9830a88..4511df2 100644
@@ -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);
net/bluetooth/hci_core.c +2 -2
index 1c9aef9..904f1e8 100644
@@ -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);
 
net/bluetooth/l2cap.c +27 -46

191 lines not on this page · raw message

Signature · 1 line
1.6.6.1
author maintainer
#50 lore raw

PATCH 50/64 Bluetooth: Refactor l2cap_retransmit_frame()

From: Gustavo F. Padovan <[email protected]>

Make the code flow cleaner and changes the function to void. It also fixes a potential NULL dereference with skb.

---
 net/bluetooth/l2cap.c |   53 +++++++++++++++++++++++++------------------------
 1 files changed, 27 insertions(+), 26 deletions(-)
net/bluetooth/l2cap.c +27 -26
index 7e74d5b..1c35c32 100644
@@ -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)
Signature · 1 line
1.6.6.1
author maintainer
#51 lore raw

PATCH 51/64 Bluetooth: Implement missing parts of the Invalid Frame Detection

From: Gustavo F. Padovan <[email protected]>

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.

---
 net/bluetooth/l2cap.c |  119 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 112 insertions(+), 7 deletions(-)
net/bluetooth/l2cap.c +112 -7
index 1c35c32..cfd6724 100644
@@ -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;
 
Signature · 1 line
1.6.6.1
author maintainer
#52 lore raw

PATCH 52/64 Bluetooth: Completes the I-frame tx_seq check logic on RECV

From: João Paulo Rechi Vita <[email protected]>

Add checks for invalid tx_seq and fixes the duplicated tx_seq check.

---
 net/bluetooth/l2cap.c |   40 ++++++++++++++++++++++++++++++++++++----
 1 files changed, 36 insertions(+), 4 deletions(-)
net/bluetooth/l2cap.c +36 -4
index cfd6724..481cec2 100644
@@ -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)
Signature · 1 line
1.6.6.1
author maintainer
#53 lore raw

PATCH 53/64 Bluetooth: Implement Local Busy Condition handling

From: Gustavo F. Padovan <[email protected]>

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.

---
 include/net/bluetooth/l2cap.h |    6 ++
 net/bluetooth/l2cap.c         |  187 ++++++++++++++++++++++++++++++++++++-----
 2 files changed, 172 insertions(+), 21 deletions(-)
include/net/bluetooth/l2cap.h +6 -0
index 8942c2f..d0185cc 100644
@@ -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));
net/bluetooth/l2cap.c +166 -21

313 lines not on this page · raw message

Signature · 1 line
1.6.6.1
author maintainer
#54 lore raw

PATCH 54/64 Bluetooth: Add wait_queue to wait ack of all sent packets

From: Gustavo F. Padovan <[email protected]>

To guarantee that all packets we sent were received we need to wait for theirs ack before shutdown the socket.

---
 net/bluetooth/l2cap.c |   34 ++++++++++++++++++++++++++++++++++
 1 files changed, 34 insertions(+), 0 deletions(-)
net/bluetooth/l2cap.c +34 -0
index 103e4b5..9d514f9 100644
@@ -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);
Signature · 1 line
1.6.6.1
author maintainer
#55 lore raw

PATCH 55/64 Bluetooth: Fix race condition on l2cap_ertm_send()

From: Gustavo F. Padovan <[email protected]>

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

---
 include/net/bluetooth/l2cap.h |    1 +
 net/bluetooth/l2cap.c         |   99 +++++++++++++++++++++++++++--------------
 2 files changed, 67 insertions(+), 33 deletions(-)
include/net/bluetooth/l2cap.h +1 -0
index d0185cc..7c695bf 100644
@@ -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;
net/bluetooth/l2cap.c +66 -33

200 lines not on this page · raw message

Signature · 1 line
1.6.6.1
author maintainer
#56 lore raw

PATCH 56/64 Bluetooth: Prevents buffer overflow on l2cap_ertm_reassembly_sdu()

From: Gustavo F. Padovan <[email protected]>

The checks should be done before the the memcpy to avoid buffer overflow.

---
 net/bluetooth/l2cap.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
net/bluetooth/l2cap.c +4 -4
index fe663e9..9ef01c3 100644
@@ -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);
Signature · 1 line
1.6.6.1
author maintainer
#57 lore raw

PATCH 57/64 Bluetooth: Fix spec error in the RemoteBusy Logic

From: Gustavo F. Padovan <[email protected]>

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.

---
 net/bluetooth/l2cap.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
net/bluetooth/l2cap.c +2 -1
index 9ef01c3..ba49f9a 100644
@@ -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) {
Signature · 1 line
1.6.6.1
author maintainer
#58 lore raw

PATCH 58/64 Bluetooth: Create per controller workqueue

Instead of having a global workqueue for all controllers, it makes more sense to have a workqueue per controller.

---
 include/net/bluetooth/hci_core.h |    2 ++
 net/bluetooth/hci_core.c         |   14 ++++++++++++++
 net/bluetooth/hci_sysfs.c        |   16 +++-------------
 3 files changed, 19 insertions(+), 13 deletions(-)
include/net/bluetooth/hci_core.h +2 -0
index 4511df2..e42f6ed 100644
@@ -107,6 +107,8 @@ struct hci_dev {
 	unsigned long	acl_last_tx;
 	unsigned long	sco_last_tx;
 
+	struct workqueue_struct	*workqueue;
+
 	struct tasklet_struct	cmd_task;
 	struct tasklet_struct	rx_task;
 	struct tasklet_struct	tx_task;
net/bluetooth/hci_core.c +14 -0
index 904f1e8..5e83f8e 100644
@@ -37,6 +37,7 @@
 #include <linux/fcntl.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
+#include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/rfkill.h>
@@ -928,6 +929,10 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	write_unlock_bh(&hci_dev_list_lock);
 
+	hdev->workqueue = create_singlethread_workqueue(hdev->name);
+	if (!hdev->workqueue)
+		goto nomem;
+
 	hci_register_sysfs(hdev);
 
 	hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
@@ -942,6 +947,13 @@ int hci_register_dev(struct hci_dev *hdev)
 	hci_notify(hdev, HCI_DEV_REG);
 
 	return id;
+
+nomem:
+	write_lock_bh(&hci_dev_list_lock);
+	list_del(&hdev->list);
+	write_unlock_bh(&hci_dev_list_lock);
+
+	return -ENOMEM;
 }
 EXPORT_SYMBOL(hci_register_dev);
 
@@ -970,6 +982,8 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
 	hci_unregister_sysfs(hdev);
 
+	destroy_workqueue(hdev->workqueue);
+
 	__hci_dev_put(hdev);
 
 	return 0;
net/bluetooth/hci_sysfs.c +3 -13
index 0e8e1a5..a978449 100644
@@ -14,8 +14,6 @@ static struct class *bt_class;
 struct dentry *bt_debugfs = NULL;
 EXPORT_SYMBOL_GPL(bt_debugfs);
 
-static struct workqueue_struct *bt_workq;
-
 static inline char *link_typetostr(int type)
 {
 	switch (type) {
@@ -161,14 +159,14 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
 {
 	BT_DBG("conn %p", conn);
 
-	queue_work(bt_workq, &conn->work_add);
+	queue_work(conn->hdev->workqueue, &conn->work_add);
 }
 
 void hci_conn_del_sysfs(struct hci_conn *conn)
 {
 	BT_DBG("conn %p", conn);
 
-	queue_work(bt_workq, &conn->work_del);
+	queue_work(conn->hdev->workqueue, &conn->work_del);
 }
 
 static inline char *host_bustostr(int bus)
@@ -487,17 +485,11 @@ void hci_unregister_sysfs(struct hci_dev *hdev)
 
 int __init bt_sysfs_init(void)
 {
-	bt_workq = create_singlethread_workqueue("bluetooth");
-	if (!bt_workq)
-		return -ENOMEM;
-
 	bt_debugfs = debugfs_create_dir("bluetooth", NULL);
 
 	bt_class = class_create(THIS_MODULE, "bluetooth");
-	if (IS_ERR(bt_class)) {
-		destroy_workqueue(bt_workq);
+	if (IS_ERR(bt_class))
 		return PTR_ERR(bt_class);
-	}
 
 	return 0;
 }
@@ -507,6 +499,4 @@ void bt_sysfs_cleanup(void)
 	class_destroy(bt_class);
 
 	debugfs_remove_recursive(bt_debugfs);
-
-	destroy_workqueue(bt_workq);
 }
Signature · 1 line
1.6.6.1
author maintainer
#59 lore raw

PATCH 59/64 Bluetooth: Fix storing negative values as unsigned char

From: Dan Carpenter <[email protected]>

This is mostly cleanup. There is only one caller and it just checks for non-zero return values. Still "ret" should be int because we want to return -EINVAL on errors.

---
 drivers/bluetooth/btmrvl_main.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/bluetooth/btmrvl_main.c +1 -1
index 53a43ad..49ec89c 100644
@@ -66,7 +66,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
 {
 	struct btmrvl_adapter *adapter = priv->adapter;
 	struct btmrvl_event *event;
-	u8 ret = 0;
+	int ret = 0;
 
 	event = (struct btmrvl_event *) skb->data;
 	if (event->ec != 0xff) {
Signature · 1 line
1.6.6.1
author maintainer
#60 lore raw

PATCH 60/64 Bluetooth: Decode btmrvl MODULE_BRINGUP_REG response correctly

From: Bing Zhao <[email protected]>

The MODULE_BRINGUP_REQ command response returns success with either 0x00 or 0x0c.

---
 drivers/bluetooth/btmrvl_drv.h  |    5 ++++-
 drivers/bluetooth/btmrvl_main.c |    6 ++++--
 2 files changed, 8 insertions(+), 3 deletions(-)
drivers/bluetooth/btmrvl_drv.h +4 -1
index 2047275..da68c62 100644
@@ -88,8 +88,11 @@ struct btmrvl_private {
 #define BT_CMD_HOST_SLEEP_ENABLE	0x5A
 #define BT_CMD_MODULE_CFG_REQ		0x5B
 
-/* Sub-commands: Module Bringup/Shutdown Request */
+/* Sub-commands: Module Bringup/Shutdown Request/Response */
 #define MODULE_BRINGUP_REQ		0xF1
+#define MODULE_BROUGHT_UP		0x00
+#define MODULE_ALREADY_UP		0x0C
+
 #define MODULE_SHUTDOWN_REQ		0xF2
 
 #define BT_EVENT_POWER_STATE		0x20
drivers/bluetooth/btmrvl_main.c +4 -2
index 49ec89c..87d0d3d 100644
@@ -112,8 +112,10 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
 	case BT_CMD_MODULE_CFG_REQ:
 		if (priv->btmrvl_dev.sendcmdflag &&
 				event->data[1] == MODULE_BRINGUP_REQ) {
-			BT_DBG("EVENT:%s", (event->data[2]) ?
-				"Bring-up failed" : "Bring-up succeed");
+			BT_DBG("EVENT:%s",
+				((event->data[2] == MODULE_BROUGHT_UP) ||
+				(event->data[2] == MODULE_ALREADY_UP)) ?
+				"Bring-up succeed" : "Bring-up failed");
 		} else if (priv->btmrvl_dev.sendcmdflag &&
 				event->data[1] == MODULE_SHUTDOWN_REQ) {
 			BT_DBG("EVENT:%s", (event->data[2]) ?
Signature · 1 line
1.6.6.1
author maintainer
#61 lore raw

PATCH 61/64 Bluetooth: Separate btmrvl_register_hdev() from btmrvl_add_card()

From: Bing Zhao <[email protected]>

Move btmrvl hdev registration code out of btmrvl_add_card(). New function btmrvl_register_hdev() is added.

---
 drivers/bluetooth/btmrvl_drv.h  |    1 +
 drivers/bluetooth/btmrvl_main.c |   75 ++++++++++++++++++++++----------------
 drivers/bluetooth/btmrvl_sdio.c |    7 +++-
 3 files changed, 50 insertions(+), 33 deletions(-)
drivers/bluetooth/btmrvl_drv.h +1 -0
index da68c62..bf6d54f 100644
@@ -126,6 +126,7 @@ struct btmrvl_event {
 
 /* Prototype of global function */
 
+int btmrvl_register_hdev(struct btmrvl_private *priv);
 struct btmrvl_private *btmrvl_add_card(void *card);
 int btmrvl_remove_card(struct btmrvl_private *priv);
 
drivers/bluetooth/btmrvl_main.c +43 -32

112 lines not on this page · raw message

drivers/bluetooth/btmrvl_sdio.c +6 -1
index 0dba76a..df0773e 100644
@@ -931,7 +931,12 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 	priv->hw_host_to_card = btmrvl_sdio_host_to_card;
 	priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
 
-	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+	if (btmrvl_register_hdev(priv)) {
+		BT_ERR("Register hdev failed!");
+		ret = -ENODEV;
+		goto disable_host_int;
+	}
+
 	priv->btmrvl_dev.psmode = 1;
 	btmrvl_enable_ps(priv);
 
Signature · 1 line
1.6.6.1
author maintainer
#62 lore raw

PATCH 62/64 Bluetooth: Set hdev->dev_type based on Marvell device type

From: Bing Zhao <[email protected]>

Get the device type from MODULE_BRINGUP_REQ command response.

---
 drivers/bluetooth/btmrvl_drv.h  |    2 ++
 drivers/bluetooth/btmrvl_main.c |    9 +++++++++
 2 files changed, 11 insertions(+), 0 deletions(-)
drivers/bluetooth/btmrvl_drv.h +2 -0
index bf6d54f..bed0ba6 100644
@@ -42,6 +42,8 @@ struct btmrvl_device {
 	void *card;
 	struct hci_dev *hcidev;
 
+	u8 dev_type;
+
 	u8 tx_dnld_rdy;
 
 	u8 psmode;
drivers/bluetooth/btmrvl_main.c +9 -0
index ec48bfe..ee37ef0 100644
@@ -116,6 +116,13 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
 				((event->data[2] == MODULE_BROUGHT_UP) ||
 				(event->data[2] == MODULE_ALREADY_UP)) ?
 				"Bring-up succeed" : "Bring-up failed");
+
+			if (event->length > 3)
+				priv->btmrvl_dev.dev_type = event->data[3];
+			else
+				priv->btmrvl_dev.dev_type = HCI_BREDR;
+
+			BT_DBG("dev_type: %d", priv->btmrvl_dev.dev_type);
 		} else if (priv->btmrvl_dev.sendcmdflag &&
 				event->data[1] == MODULE_SHUTDOWN_REQ) {
 			BT_DBG("EVENT:%s", (event->data[2]) ?
@@ -549,6 +556,8 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
 
 	btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
 
+	hdev->dev_type = priv->btmrvl_dev.dev_type;
+
 	ret = hci_register_dev(hdev);
 	if (ret < 0) {
 		BT_ERR("Can not register HCI device");
Signature · 1 line
1.6.6.1
author maintainer
#63 lore raw

PATCH 63/64 Bluetooth: Use strict_strtoul instead of simple_strtoul

From: Tomas Winkler <[email protected]>

Use strict_strtoul as suggested by checkpatch.pl for more strict input checking.

---
 net/bluetooth/hci_sysfs.c |   18 ++++++------------
 1 files changed, 6 insertions(+), 12 deletions(-)
net/bluetooth/hci_sysfs.c +6 -12
index a978449..463ffa4 100644
@@ -281,11 +281,9 @@ static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *at
 static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct hci_dev *hdev = dev_get_drvdata(dev);
-	char *ptr;
-	__u32 val;
+	unsigned long val;
 
-	val = simple_strtoul(buf, &ptr, 10);
-	if (ptr == buf)
+	if (strict_strtoul(buf, 0, &val) < 0)
 		return -EINVAL;
 
 	if (val != 0 && (val < 500 || val > 3600000))
@@ -305,11 +303,9 @@ static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribu
 static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct hci_dev *hdev = dev_get_drvdata(dev);
-	char *ptr;
-	__u16 val;
+	unsigned long val;
 
-	val = simple_strtoul(buf, &ptr, 10);
-	if (ptr == buf)
+	if (strict_strtoul(buf, 0, &val) < 0)
 		return -EINVAL;
 
 	if (val < 0x0002 || val > 0xFFFE || val % 2)
@@ -332,11 +328,9 @@ static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribu
 static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct hci_dev *hdev = dev_get_drvdata(dev);
-	char *ptr;
-	__u16 val;
+	unsigned long val;
 
-	val = simple_strtoul(buf, &ptr, 10);
-	if (ptr == buf)
+	if (strict_strtoul(buf, 0, &val) < 0)
 		return -EINVAL;
 
 	if (val < 0x0002 || val > 0xFFFE || val % 2)
Signature · 1 line
1.6.6.1
author maintainer
#64 lore raw

PATCH 64/64 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.

---
 net/bluetooth/l2cap.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
net/bluetooth/l2cap.c +4 -4
index ba49f9a..673a368 100644
@@ -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);
 }
Signature · 1 line
1.6.6.1
maintainer
#65 lore raw
In reply to Marcel Holtmann

From: Marcel Holtmann <[email protected]>
Date: Mon, 10 May 2010 11:36:50 +0200

Quoted 2 lines

this is the big merge for the L2CAP Enhanced Retransmission support work done by Gustavo F. Padovan. All other changes are small cleanups.

Yeah, "big", as in "too big".

Please sync with me more often so you don't have to obliterate the list with unacceptable 64 posting patch bombs. Nobody is going to really review such a huge patch set in any serious manner, which makes posting those patches almost worthless.

Anything more than about 10 or 20 at a time is way too much.

author maintainer
#66 lore raw

Hi Dave,

Quoted 11 lines
Quoted 2 lines

this is the big merge for the L2CAP Enhanced Retransmission support work done by Gustavo F. Padovan. All other changes are small cleanups.

Yeah, "big", as in "too big".

Please sync with me more often so you don't have to obliterate the list with unacceptable 64 posting patch bombs. Nobody is going to really review such a huge patch set in any serious manner, which makes posting those patches almost worthless.

Anything more than about 10 or 20 at a time is way too much.

normally we don't have any big changes in the Bluetooth kernel side. This is the first one that adds a big set of features. And it is limited to the L2CAP layer. I took it out of last kernel release since it was incomplete and would not have been useful. Right now it is in a stage where it becomes usable. Only new profiles like the Health Medical stuff is making use of these features for now. However in the future more and more profile will requires support for it.

The number of patches are not getting smaller. Except I arbitrarily merge them together. I am not planning to do that since I think it is not a good idea at all. And the patches have been reviewed by João Paulo Rechi Vita who worked with Gustavo on these changes.

So do you want to postpone this for 2.6.35 merge window?

Regards

Marcel

maintainer
#67 lore raw

From: Marcel Holtmann <[email protected]>
Date: Mon, 10 May 2010 12:41:09 +0200

Quoted 8 lines

normally we don't have any big changes in the Bluetooth kernel side. This is the first one that adds a big set of features. And it is limited to the L2CAP layer. I took it out of last kernel release since it was incomplete and would not have been useful. Right now it is in a stage where it becomes usable. Only new profiles like the Health Medical stuff is making use of these features for now. However in the future more and more profile will requires support for it.

Quoted 4 lines

The number of patches are not getting smaller. Except I arbitrarily merge them together. I am not planning to do that since I think it is not a good idea at all. And the patches have been reviewed by João Paulo Rechi Vita who worked with Gustavo on these changes.

It is your problem if you don't think there is any value to people reviewing the stuff you're asking me to merge into the tree.

Quoted 1 line

So do you want to postpone this for 2.6.35 merge window?

I'll pull this stuff into net-next-2.6 after I give it a glance over but you can't operate like this in the future.

Once you have about 10 commits ready in your tree, just push it to me, don't delay.

maintainer
#68 lore raw
In reply to Marcel Holtmann

Ok, I pulled this.

But patch #32 needs to be fixed. That TX window thing is, if anything, a socket option not some obscure module load parameter.

Doing it with a module parameter means that you can't make it so that only some sockets (or some network paths) use a certain TX window value and other's not.

Another alternative is to, as implied, make it a route metric or similar.

Anything but a module option is appropriate for this.

author maintainer
#69 lore raw

Hi Dave,

Quoted 5 lines

Ok, I pulled this.

But patch #32 needs to be fixed. That TX window thing is, if anything, a socket option not some obscure module load parameter.

Quoted 8 lines

Doing it with a module parameter means that you can't make it so that only some sockets (or some network paths) use a certain TX window value and other's not.

Another alternative is to, as implied, make it a route metric or similar.

Anything but a module option is appropriate for this.

actually that was only a module option so we can easily test this at an UnPlugFest. I think it can be removed all together now. We don't need it anymore. I check with Gustavo.

Regards

Marcel

maintainer
#70 lore raw
In reply to David Miller

More problems.

In the future, don't fix things like you did in:

"Bluetooth: Fix issues where sk_sleep() helper is needed now"

That's something you take care of inside of the merge which causes the build problems.

It's even trivial:

bash$ cd bluetooth-next-2.6
bash$ git pull .../net-next-2.6/.git
bash$ make
... build fails because sk_sleep() stuff ...
bash$ emacs ...
bash$ make
... build succeeds now ...
bash$ git commit --amend file1.c file2.c ...

and add some mention in the amended merge commit about what you did to take care of the sk_sleep() stuff. That final commit command will update the merge commit so that it has the build fix included in it and therefore at any particular commit the tree does not fail to build.

Otherwise you create a situation where the tree is not bisectable at all, if someone bisects to the commit before the sk_sleep() fix the tree won't build, and this makes bug hunting more painful than it needs to be.

maintainer
#71 lore raw

BT_L2CAP_EXT_FEATURES makes no sense at all...

If someone can rebuild their kernel, they can just as equally add an entry to /etc/sysctl.conf to turn that thing on early in the boot process.

It's not like you're going to get distributions to enable this kernel config option by default to get "wider coverage" for testing this new feature.

Please just toss this thing, and please don't post so much of this kind of stuff in one go ever again, this way problems like this and the other one's can be caught early, rather than my having to pick apart several problematic changes in one huge pass. :-/

Thanks.