* [PATCH 10/34] Bluetooth: Use a l2cap_pinfo struct instead l2cap_pi() macro
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1270153432-6477-10-git-send-email-padovan@profusion.mobi>
Trivial clean up.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 4dd130d..428be03 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1300,7 +1300,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);
}
@@ -1353,7 +1353,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);
}
@@ -1401,7 +1401,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);
}
@@ -3576,10 +3576,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;
}
@@ -3688,7 +3688,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;
}
--
1.6.4.4
^ permalink raw reply related
* [PATCH 09/34] Bluetooth: Add Recv RR (P=0)(F=0) for SREJ_SENT state on ERTM
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1270153432-6477-9-git-send-email-padovan@profusion.mobi>
This finishes the implementation of Recv RR (P=0)(F=0) for the Enhanced
Retransmission Mode on L2CAP.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 2e1884b..4dd130d 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3509,7 +3509,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;
--
1.6.4.4
^ permalink raw reply related
* [PATCH 08/34] Bluetooth: Move set of P-bit to l2cap_send_sframe()
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1270153432-6477-8-git-send-email-padovan@profusion.mobi>
Abstract the send of of P-bit and avoids code duplication like we
did with the setting of F-bit.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 6368cb2..2e1884b 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -357,6 +357,11 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
}
+ if (pi->conn_state & L2CAP_CONN_SEND_PBIT) {
+ control |= L2CAP_CTRL_POLL;
+ pi->conn_state &= ~L2CAP_CONN_SEND_PBIT;
+ }
+
skb = bt_skb_alloc(count, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
@@ -3356,10 +3361,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);
--
1.6.4.4
^ permalink raw reply related
* [PATCH 07/34] Bluetooth: Implement SendAck() Action on ERTM.
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1270153432-6477-7-git-send-email-padovan@profusion.mobi>
Shall be used to ack received frames, It must decide type of
acknowledgment between a RR frame, a RNR frame or transmission of
pending I-frames.
It also modifies l2cap_ertm_send() to report the number of frames sent.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 41 +++++++++++++++++++++++++++++------------
1 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 03caa2c..6368cb2 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -352,6 +352,11 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
count = min_t(unsigned int, conn->mtu, hlen);
control |= L2CAP_CTRL_FRAME_TYPE;
+ if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+ control |= L2CAP_CTRL_FINAL;
+ pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+ }
+
skb = bt_skb_alloc(count, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
@@ -1363,7 +1368,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;
@@ -1413,8 +1418,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;
}
@@ -1673,7 +1697,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;
@@ -3170,10 +3194,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);
}
}
@@ -3354,7 +3374,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;
@@ -3441,11 +3460,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;
}
--
1.6.4.4
^ permalink raw reply related
* [PATCH 06/34] Bluetooth: Fix expected_tx_seq calculation on L2CAP
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1270153432-6477-6-git-send-email-padovan@profusion.mobi>
All operation related to the txWindow should be modulo 64.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 36fac64..03caa2c 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3660,7 +3660,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);
--
1.6.4.4
^ permalink raw reply related
* [PATCH 05/34] Bluetooth: Check if SDU size is greater than MTU on L2CAP
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1270153432-6477-5-git-send-email-padovan@profusion.mobi>
After reassembly the SDU we need to check his size. It can't overflow
the MTU size.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index e78fc16..36fac64 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3269,15 +3269,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;
}
--
1.6.4.4
^ permalink raw reply related
* [PATCH 04/34] Bluetooth: Check the minimum {I,S}-frame size into L2CAP
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1270153432-6477-4-git-send-email-padovan@profusion.mobi>
All packets with size fewer than the minimum specified is dropped.
Note that the size of the l2cap basic header, FCS and SAR fields are
already subtracted of len at the moment of the size check.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 14 +++++++++++---
1 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index a020b9f..e78fc16 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3619,10 +3619,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;
@@ -3637,7 +3644,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))
--
1.6.4.4
^ permalink raw reply related
* [PATCH 03/34] Bluetooth: Fix memory leak of S-frames into L2CAP
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1270153432-6477-3-git-send-email-padovan@profusion.mobi>
l2cap_data_channel do not free the S-frame, so we free it here.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index ab3f0c4..a020b9f 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3559,6 +3559,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
break;
}
+ kfree_skb(skb);
return 0;
}
--
1.6.4.4
^ permalink raw reply related
* [PATCH 02/34] Bluetooth: Support case with F bit set under WAIT_F state.
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1270153432-6477-2-git-send-email-padovan@profusion.mobi>
On receipt of a F=1 under WAIT_F state ERTM shall stop monitor timer and
start retransmission timer (if there are unacked frames).
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 22 ++++++++++++++--------
1 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 18328a4..ab3f0c4 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3356,6 +3356,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);
@@ -3445,6 +3452,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) {
@@ -3464,14 +3478,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);
--
1.6.4.4
^ permalink raw reply related
* [PATCH 01/34] Bluetooth: Implement 'Send IorRRorRNR' event
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1270153432-6477-1-git-send-email-padovan@profusion.mobi>
After receive a RR with P bit set ERTM shall use this funcion to choose
what type of frame to reply with F bit = 1.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 20 ++++++++++--------
net/bluetooth/l2cap.c | 44 +++++++++++++++++++++++++++++++++++++---
2 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 17a689f..d9c20c3 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -320,7 +320,7 @@ struct l2cap_pinfo {
__u8 conf_req[64];
__u8 conf_len;
__u8 conf_state;
- __u8 conn_state;
+ __u16 conn_state;
__u8 next_tx_seq;
__u8 expected_ack_seq;
@@ -328,6 +328,7 @@ struct l2cap_pinfo {
__u8 buffer_seq;
__u8 buffer_seq_srej;
__u8 srej_save_reqseq;
+ __u8 frames_sent;
__u8 unacked_frames;
__u8 retry_count;
__u8 num_to_ack;
@@ -367,14 +368,15 @@ struct l2cap_pinfo {
#define L2CAP_CONF_MAX_CONF_REQ 2
#define L2CAP_CONF_MAX_CONF_RSP 2
-#define L2CAP_CONN_SAR_SDU 0x01
-#define L2CAP_CONN_SREJ_SENT 0x02
-#define L2CAP_CONN_WAIT_F 0x04
-#define L2CAP_CONN_SREJ_ACT 0x08
-#define L2CAP_CONN_SEND_PBIT 0x10
-#define L2CAP_CONN_REMOTE_BUSY 0x20
-#define L2CAP_CONN_LOCAL_BUSY 0x40
-#define L2CAP_CONN_REJ_ACT 0x80
+#define L2CAP_CONN_SAR_SDU 0x0001
+#define L2CAP_CONN_SREJ_SENT 0x0002
+#define L2CAP_CONN_WAIT_F 0x0004
+#define L2CAP_CONN_SREJ_ACT 0x0008
+#define L2CAP_CONN_SEND_PBIT 0x0010
+#define L2CAP_CONN_REMOTE_BUSY 0x0020
+#define L2CAP_CONN_LOCAL_BUSY 0x0040
+#define L2CAP_CONN_REJ_ACT 0x0080
+#define L2CAP_CONN_SEND_FBIT 0x0100
#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \
jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 7794a2e..18328a4 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1382,6 +1382,10 @@ static int l2cap_ertm_send(struct sock *sk)
bt_cb(skb)->retries++;
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+ if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+ control |= L2CAP_CTRL_FINAL;
+ pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+ }
control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
@@ -1403,6 +1407,7 @@ static int l2cap_ertm_send(struct sock *sk)
pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
pi->unacked_frames++;
+ pi->frames_sent++;
if (skb_queue_is_last(TX_QUEUE(sk), skb))
sk->sk_send_head = NULL;
@@ -2186,6 +2191,7 @@ static inline void l2cap_ertm_init(struct sock *sk)
l2cap_pi(sk)->unacked_frames = 0;
l2cap_pi(sk)->buffer_seq = 0;
l2cap_pi(sk)->num_to_ack = 0;
+ l2cap_pi(sk)->frames_sent = 0;
setup_timer(&l2cap_pi(sk)->retrans_timer,
l2cap_retrans_timeout, (unsigned long) sk);
@@ -3139,6 +3145,39 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb)
return 0;
}
+static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
+{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ u16 control = 0;
+
+ pi->frames_sent = 0;
+ pi->conn_state |= L2CAP_CONN_SEND_FBIT;
+
+ control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+
+ if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+ control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL;
+ l2cap_send_sframe(pi, control);
+ pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+
+ }
+
+ if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0)
+ __mod_retrans_timer();
+
+ l2cap_ertm_send(sk);
+
+ if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
+ pi->frames_sent == 0) {
+ control |= L2CAP_SUPER_RCV_READY;
+ if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+ control |= L2CAP_CTRL_FINAL;
+ pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+ }
+ l2cap_send_sframe(pi, control);
+ }
+}
+
static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar)
{
struct sk_buff *next_skb;
@@ -3409,10 +3448,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
switch (rx_control & L2CAP_CTRL_SUPERVISE) {
case L2CAP_SUPER_RCV_READY:
if (rx_control & L2CAP_CTRL_POLL) {
- u16 control = L2CAP_CTRL_FINAL;
- control |= L2CAP_SUPER_RCV_READY |
- (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT);
- l2cap_send_sframe(l2cap_pi(sk), control);
+ l2cap_send_i_or_rr_or_rnr(sk);
pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
} else if (rx_control & L2CAP_CTRL_FINAL) {
--
1.6.4.4
^ permalink raw reply related
* Patches for eL2CAP
From: Gustavo F. Padovan @ 2010-04-01 20:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
Hi Marcel,
Here are all patches rebased against -rc3. Most of then are a resend unless
the last five patches.
^ permalink raw reply
* obexd and phonebook-ebook.c (PBAP support)
From: commerce @ 2010-04-01 15:11 UTC (permalink / raw)
To: linux-bluetooth
Hi,
Is it possible that obexd has to call g_type_init() if phonebook-ebook
is used?
I think when you call e_book_new_default_addressbook() somewhere down
gconf_client_get_default() is called and it insists that g_type_init()
is called prior to its use.
I tried to make obexd work on my N900, but I did not get there.
My car kit does not use PBAP because it finds the Nokia SyncML profile
and uses it, but the N900 does not communicate with bluetooth devices
other than PC or Mobiles via SyncML.
Is there a way to unregister a service from SDP?
Regards,
--
Harald
^ permalink raw reply
* [PATCH] Added Host level support for Atheros AR3xxx Bluetooth Chip
From: suraj @ 2010-03-31 10:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, Luis.Rodriguez, Jothikumar.Mothilal
In-Reply-To: <1269408445.23163.0.camel@atheros013-desktop>
Added support for Atheros AR3xxx Bluetooth chip
Implemented feature to download firmware configuration from host.
Signed-off-by: Suraj <suraj@atheros.com>
---
Makefile.tools | 1 +
tools/hciattach.8 | 6 +
tools/hciattach.c | 159 +++++++-
tools/hciattach.h | 2 +
tools/hciattach_ar3k.c | 1228 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 1395 insertions(+), 1 deletions(-)
create mode 100755 tools/hciattach_ar3k.c
diff --git a/Makefile.tools b/Makefile.tools
index 2735d68..48cf097 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -23,6 +23,7 @@ tools_l2ping_LDADD = lib/libbluetooth.la
tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
tools/hciattach_st.c \
tools/hciattach_ti.c \
+ tools/hciattach_ar3k.c \
tools/hciattach_tialt.c
tools_hciattach_LDADD = lib/libbluetooth.la
diff --git a/tools/hciattach.8 b/tools/hciattach.8
index f750222..af648f2 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -49,6 +49,12 @@ specific identifier. Currently supported types are
.B any
Unspecified HCI_UART interface, no vendor specific options
.TP
+.B ar3kalt
+Atheros AR3xxx based modules with power management disabled
+.TP
+.B ar3k
+Atheros AR3xxx based modules
+.TP
.B ericsson
Ericsson based modules
.TP
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 364c5ff..3557554 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -653,7 +653,156 @@ static int csr(int fd, struct uart_t *u, struct termios *ti)
}
/*
- * Silicon Wave specific initialization
+ * Atheros AR3xxx specific initialization code with power management disabled.
+ * Suraj Sumangala <Suraj@Atheros.com>
+ */
+static int ar3kpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ int dev_id, dd;
+ struct timespec tm = {0, 50000};
+ int status = 0;
+
+
+ dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
+ if (dev_id < 0) {
+ perror("cannot get device id");
+ return -1;
+ }
+
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ return -1;
+ }
+ sleep(2);
+ /* send command with Sleep feature disabled */
+ hci_send_cmd(dd, OGF_VENDOR_CMD, 0x04, 1, &status);
+
+ nanosleep(&tm, NULL);
+ hci_close_dev(dd);
+
+ return 0;
+
+}
+/*
+ * Atheros AR3xxx specific initialization post callback
+ * with power management enabled
+ * Suraj Sumangala <Suraj@Atheros.com>
+ */
+static int ar3kpmpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ int dev_id, dd;
+ struct timespec tm = {0, 50000};
+ int status = 1;
+
+
+ dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
+ if (dev_id < 0) {
+ perror("cannot get device id");
+ return -1;
+ }
+
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ return -1;
+ }
+ sleep(2);
+ /* send command with Sleep feature disabled */
+ if (hci_send_cmd(dd, OGF_VENDOR_CMD, 0x04, 1, &status) < 0)
+ perror("sleep enable command not sent");
+
+ nanosleep(&tm, NULL);
+ hci_close_dev(dd);
+
+ return 0;
+}
+/*
+ * Atheros AR3xxx specific initialization
+ * Suraj Sumangala <Suraj@Atheros.com>
+ */
+static int ar3kinit(int fd, struct uart_t *u, struct termios *ti)
+{
+ struct timespec tm = { 0, 500000 };
+ unsigned char cmd[14], rsp[100];
+ int r;
+ int baud;
+
+ /* Download PS and patch */
+ r = ath_ps_download(fd);
+ if (r < 0) {
+ perror("Failed to Download configuration");
+ return -1;
+ }
+ /* Write BDADDR if user has provided any */
+ if (u->bdaddr != NULL) {
+ /* Set BD_ADDR */
+ memset(cmd, 0, sizeof(cmd));
+ memset(rsp, 0, sizeof(rsp));
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x0B;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x0A;
+ cmd[4] = 0x01;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x06;
+ str2ba(u->bdaddr, (bdaddr_t *) (cmd + 8));
+
+ /* Send command */
+ if (write(fd, cmd, 14) != 14) {
+ fprintf(stderr, "Failed to write BD_ADDR command\n");
+ return -1;
+ }
+
+ /* Read reply */
+ if (read_hci_event(fd, rsp, 10) < 0) {
+ fprintf(stderr, "Failed to set BD_ADDR\n");
+ return -1;
+ }
+ }
+
+ /* Send HCI Reset to write the configuration */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x03;
+ cmd[2] = 0x0c;
+ cmd[3] = 0x00;
+ /* Send reset command */
+ r = write(fd, cmd, 4);
+
+ if (r != 4)
+ return -1;
+
+ nanosleep(&tm, NULL);
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -1;
+
+ /* Set baud rate command,
+ * set controller baud rate to user specified value */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x0C;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x02;
+ baud = u->speed/100;
+ cmd[4] = (char)baud;
+ cmd[5] = (char)(baud >> 8);
+
+ if (write(fd, cmd, 6) != 6) {
+ perror("Failed to write init command");
+ return -1;
+ }
+
+ /* Wait for the command complete event for Baud rate change Command */
+ nanosleep(&tm, NULL);
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -1;
+
+ return 0;
+}
+/*
+ * Silicon Wave specific initialization
* Thomas Moser <thomas.moser@tmoser.ch>
*/
static int swave(int fd, struct uart_t *u, struct termios *ti)
@@ -1071,6 +1220,14 @@ struct uart_t uart[] = {
/* Broadcom BCM2035 */
{ "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },
+ /* ATHEROS AR3xxx */
+ { "ar3kalt", 0x0000, 0x0000, HCI_UART_ATH,
+ 115200, 115200, FLOW_CTL, NULL, ar3kinit, ar3kpost },
+
+ { "ar3k", 0x0000, 0x0000, HCI_UART_ATH,
+ 115200, 115200, FLOW_CTL, NULL, ar3kinit, ar3kpmpost },
+
+
{ NULL, 0 }
};
diff --git a/tools/hciattach.h b/tools/hciattach.h
index 867563b..5b68668 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -36,6 +36,7 @@
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_ATH 5
int read_hci_event(int fd, unsigned char* buf, int size);
int set_speed(int fd, struct termios *ti, int speed);
@@ -45,3 +46,4 @@ int texas_post(int fd, struct termios *ti);
int texasalt_init(int fd, int speed, struct termios *ti);
int stlc2500_init(int fd, bdaddr_t *bdaddr);
int bgb2xx_init(int dd, bdaddr_t *bdaddr);
+int ath_ps_download(int fd);
diff --git a/tools/hciattach_ar3k.c b/tools/hciattach_ar3k.c
new file mode 100755
index 0000000..ca418d9
--- /dev/null
+++ b/tools/hciattach_ar3k.c
@@ -0,0 +1,1228 @@
+/*
+ * Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hciattach.h"
+
+/* Helper data type declaration */
+
+#define FALSE 0
+#define TRUE 1
+
+/* The maximum number of bytes possible in a patch entry */
+#define MAX_PATCH_SIZE 20000
+
+/* Maximum HCI packets that will be formed from the Patch file */
+#define MAX_NUM_PATCH_ENTRY ((MAX_PATCH_SIZE/MAX_BYTE_LENGTH) + 1)
+
+#define FPGA_REGISTER 0x4FFC
+
+#define PS_ASIC_FILE "PS_ASIC.pst"
+#define PS_FPGA_FILE "PS_FPGA.pst"
+#define FW_PATH "/lib/firmware/"
+#define PATCH_FILE "RamPatch.txt"
+#define BDADDR_FILE "ar3kbdaddr.pst"
+
+
+
+#define PS_RESET 2
+#define PS_WRITE 1
+#define WRITE_PATCH 8
+#define PS_VERIFY_CRC 9
+#define ENABLE_PATCH 11
+
+
+#define NUM_WAKEUP_RETRY 10
+
+#define HCI_CMD_HEADER_LEN 7
+
+#define RAM_PS_REGION (1<<0)
+#define RAM_PATCH_REGION (1<<1)
+
+#define RAMPS_MAX_PS_TAGS_PER_FILE 50
+#define PS_MAX_LEN 500
+#define LINE_SIZE_MAX (PS_MAX_LEN * 2)
+
+/* Constant values used by parser */
+#define BYTES_OF_PS_DATA_PER_LINE 16
+
+#define MAX_BYTE_LENGTH 244
+
+#define skip_space(str) while (*(str) == (' ')) ((str)++)
+
+#define IS_BETWEEN(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
+
+#define tohexval(c) (isdigit(c) ? ((c) - '0') : \
+ (IS_BETWEEN((c), 'A', 'Z') ? \
+ ((c) - 'A' + 10) : ((c) - 'a' + 10)))
+
+enum ps_entry_type {
+ hex_type,
+ decimal_type
+};
+
+struct ps_tag_entry {
+ uint32_t tag_id;
+ uint32_t tag_len;
+ uint8_t *tag_data;
+};
+
+struct ps_ram_patch {
+ int16_t Len;
+ uint8_t *Data;
+};
+struct ps_data_format {
+ enum ps_entry_type data_type;
+ unsigned char is_array;
+};
+
+struct ps_cmd_packet {
+ uint8_t *Hcipacket;
+ int packetLen;
+};
+
+struct st_read_status {
+ unsigned section;
+ unsigned line_count;
+ unsigned char_cnt;
+ unsigned byte_count;
+};
+
+/* Stores the number of PS Tags */
+static uint32_t tag_count;
+
+/* Stores the number of patch commands */
+static uint32_t patch_count;
+static uint32_t total_tag_len;
+static uint32_t rom_version;
+static uint32_t build_version;
+
+struct ps_tag_entry ps_tag_entry[RAMPS_MAX_PS_TAGS_PER_FILE];
+struct ps_ram_patch ram_patch[MAX_NUM_PATCH_ENTRY];
+
+
+/* PS parser helper function */
+static void load_hci_header(uint8_t *hci_ps_cmd,
+ uint8_t opcode, int length, int index)
+{
+ hci_ps_cmd[0] = 0x0B;
+ hci_ps_cmd[1] = 0xFC;
+ hci_ps_cmd[2] = length + 4;
+ hci_ps_cmd[3] = opcode;
+ hci_ps_cmd[4] = (index & 0xFF);
+ hci_ps_cmd[5] = ((index >> 8) & 0xFF);
+ hci_ps_cmd[6] = length;
+}
+
+
+static int ath_create_ps_command(uint8_t opcode, uint32_t param_1,
+ struct ps_cmd_packet *ps_patch_packet,
+ uint32_t *index)
+{
+ uint8_t *hci_ps_cmd;
+ uint32_t len;
+ int i;
+
+ hci_ps_cmd = NULL;
+
+ switch (opcode) {
+
+ case WRITE_PATCH:
+
+ for (i = 0; i < param_1; i++) {
+ /* Allocate command buffer */
+ hci_ps_cmd =
+ (uint8_t *) malloc(ram_patch[i].Len +
+ HCI_CMD_HEADER_LEN);
+
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0,
+ ram_patch[i].Len + HCI_CMD_HEADER_LEN);
+
+ /* Update commands to buffer */
+ load_hci_header(hci_ps_cmd, opcode, ram_patch[i].Len,
+ i);
+ memcpy(ram_patch[i].Data,
+ &hci_ps_cmd[HCI_CMD_HEADER_LEN],
+ ram_patch[i].Len);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen =
+ ram_patch[i].Len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+ }
+ break;
+ case ENABLE_PATCH:
+
+ len = 0;
+ i = 0;
+
+ hci_ps_cmd = (uint8_t *) malloc(len + HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0, len + HCI_CMD_HEADER_LEN);
+
+ load_hci_header(hci_ps_cmd, opcode, len, i);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen
+ = len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+
+ break;
+ case PS_RESET:
+
+ len = 0x06;
+ i = 0;
+
+ hci_ps_cmd = (uint8_t *) malloc(len + HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0, len + HCI_CMD_HEADER_LEN);
+
+ load_hci_header(hci_ps_cmd, opcode, len, i);
+
+ hci_ps_cmd[7] = 0x00;
+ hci_ps_cmd[len + HCI_CMD_HEADER_LEN - 2] = (param_1 & 0xFF);
+ hci_ps_cmd[len + HCI_CMD_HEADER_LEN - 1] =
+ ((param_1 >> 8) & 0xFF);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen
+ = len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+
+ break;
+ case PS_WRITE:
+ for (i = 0; i < param_1; i++) {
+ hci_ps_cmd =
+ (uint8_t *) malloc(ps_tag_entry[i].tag_len +
+ HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0,
+ ps_tag_entry[i].tag_len + HCI_CMD_HEADER_LEN);
+
+ load_hci_header(hci_ps_cmd, opcode,
+ ps_tag_entry[i].tag_len,
+ ps_tag_entry[i].tag_id);
+ memcpy(&hci_ps_cmd[HCI_CMD_HEADER_LEN],
+ ps_tag_entry[i].tag_data,
+ ps_tag_entry[i].tag_len);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+
+ ps_patch_packet[*index].packetLen =
+ ps_tag_entry[i].tag_len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+ }
+ break;
+ case PS_VERIFY_CRC:
+
+ len = 0x0;
+
+ hci_ps_cmd = (uint8_t *) malloc(len + HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0, len + HCI_CMD_HEADER_LEN);
+
+ load_hci_header(hci_ps_cmd, opcode, len, param_1);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen
+ = len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+unsigned int get_input_data_format(char *line,
+ struct ps_data_format *pst_format)
+{
+ if (line[0] != '[') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ return 0;
+ }
+
+ switch (line[1]) {
+
+ case 'H':
+ case 'h':
+ if (line[2] == ':') {
+ if ((line[3] == 'a') || (line[3] == 'A')) {
+
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+
+ }
+
+ if ((line[3] == 'S') || (line[3] == 's')) {
+
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = FALSE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+
+ } else if (line[3] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 4;
+ return 0;
+ } else
+ return 1;
+
+ } else if (line[2] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 3;
+
+ return 0;
+ } else
+ return 1;
+
+ break;
+
+ case 'A':
+ case 'a':
+
+ if (line[2] == ':') {
+
+ if ((line[3] == 'h') || (line[3] == 'H')) {
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+ } else if (line[3] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 4;
+ return 0;
+ } else
+ return 1;
+
+ } else if (line[2] == ']') {
+
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 3;
+ return 0;
+
+ } else
+ return 1;
+
+ break;
+
+ case 'S':
+ case 's':
+ if (line[2] == ':') {
+
+ if ((line[3] == 'h') || (line[3] == 'H')) {
+
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+ } else if (line[3] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 4;
+ return 0;
+ } else
+ return 1;
+
+ } else if (line[2] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 3;
+ return 0;
+ } else
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+}
+
+static unsigned int read_data_in_section(char *line,
+ struct ps_data_format format_info)
+{
+ char *token_ptr = line;
+
+ if (token_ptr[0] == '[') {
+ while (token_ptr[0] != ']' && token_ptr[0] != '\0')
+ token_ptr++;
+
+ if (token_ptr[0] == '\0')
+ return 0x0FFF;
+
+ token_ptr++;
+ }
+
+ if (format_info.data_type == hex_type) {
+ if (format_info.is_array == TRUE)
+ return 0x0FFF;
+ else
+ return strtol(token_ptr, NULL, 16);
+ } else
+ return 0x0FFF;
+}
+
+static int ath_parse_file(FILE *stream)
+{
+ char *buffer;
+ char *line;
+ uint8_t tag_cnt;
+ int16_t byte_count;
+ uint32_t pos;
+ int read_count;
+ struct ps_data_format stps_data_format;
+
+ int line_read = 0;
+ struct st_read_status read_status = {
+ 0, 0, 0, 0
+ };
+
+ pos = 0;
+ buffer = NULL;
+ tag_cnt = 0;
+ byte_count = 0;
+
+ if (stream == NULL) {
+ perror("Could not open config file .\n");
+ return -1;
+ }
+
+ buffer = malloc(LINE_SIZE_MAX + 1);
+ if (NULL == buffer)
+ return -1;
+
+ while ((line = fgets(buffer, LINE_SIZE_MAX, stream)) != NULL) {
+ skip_space(line);
+
+ if ((line[0] == '/') && (line[1] == '/'))
+ continue;
+
+ if ((line[0] == '#')) {
+ if (read_status.section != 0) {
+ perror("error\n");
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ } else {
+ read_status.section = 1;
+ continue;
+ }
+ }
+
+ if ((line[0] == '/') && (line[1] == '*')) {
+
+ line += 2;
+ skip_space(line);
+ line_read = 0;
+ read_status.section = 0;
+
+ continue;
+ }
+
+ if (read_status.section == 1) {
+ skip_space(line);
+
+ if (get_input_data_format(line, &stps_data_format)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+
+ ps_tag_entry[tag_cnt].tag_id =
+ read_data_in_section(line, stps_data_format);
+ read_status.section = 2;
+
+ } else if (read_status.section == 2) {
+
+ if (get_input_data_format(line, &stps_data_format)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+
+ byte_count =
+ read_data_in_section(line, stps_data_format);
+
+ if (byte_count > LINE_SIZE_MAX / 2) {
+ if (buffer != NULL)
+ free(buffer);
+
+ return -1;
+ }
+
+ ps_tag_entry[tag_cnt].tag_len = byte_count;
+ ps_tag_entry[tag_cnt].tag_data = (uint8_t *)
+ malloc(byte_count);
+
+ read_status.section = 3;
+ read_status.line_count = 0;
+
+ } else if (read_status.section == 3) {
+
+ if (read_status.line_count == 0) {
+ if (get_input_data_format(line,
+ &stps_data_format)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+ }
+
+ skip_space(line);
+ read_status.char_cnt = 0;
+ if (line[read_status.char_cnt] == '[') {
+
+ while (line[read_status.char_cnt] != ']' &&
+ line[read_status.char_cnt] != '\0')
+ read_status.char_cnt++;
+
+ if (line[read_status.char_cnt] == ']')
+ read_status.char_cnt++;
+ else
+ read_status.char_cnt = 0;
+
+ }
+
+ read_count = (byte_count > BYTES_OF_PS_DATA_PER_LINE)
+ ? BYTES_OF_PS_DATA_PER_LINE : byte_count;
+
+ if ((stps_data_format.data_type == hex_type)
+ && stps_data_format.is_array == TRUE) {
+
+ while (read_count > 0) {
+
+ ps_tag_entry[tag_cnt].tag_data
+ [read_status.byte_count]
+ = (uint8_t)(tohexval
+ (line[read_status.char_cnt])
+ << 4)
+ | (uint8_t)(tohexval
+ (line[read_status.char_cnt + 1]));
+
+ ps_tag_entry[tag_cnt].tag_data
+ [read_status.byte_count
+ + 1] = (uint8_t)(tohexval
+ (line[read_status.char_cnt + 3])
+ << 4)
+ | (uint8_t)(tohexval
+ (line[read_status.char_cnt + 4]));
+
+ read_status.char_cnt += 6;
+ read_status.byte_count += 2;
+ read_count -= 2;
+
+ }
+
+ if (byte_count > BYTES_OF_PS_DATA_PER_LINE)
+ byte_count -= BYTES_OF_PS_DATA_PER_LINE;
+ else
+ byte_count = 0;
+ }
+
+ read_status.line_count++;
+
+ if (byte_count == 0) {
+ read_status.section = 0;
+ read_status.char_cnt = 0;
+ read_status.line_count = 0;
+ read_status.byte_count = 0;
+ } else
+ read_status.char_cnt = 0;
+
+ if ((read_status.section == 0) &&
+ (++tag_cnt == RAMPS_MAX_PS_TAGS_PER_FILE)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+
+ }
+ line_read++;
+ }
+
+ tag_count = tag_cnt;
+
+ if (tag_cnt > RAMPS_MAX_PS_TAGS_PER_FILE) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+
+ if (buffer != NULL)
+ free(buffer);
+
+ return 0;
+}
+
+static int parse_patch_file(FILE *stream)
+{
+ char byte[3];
+ char line[MAX_BYTE_LENGTH + 1];
+ int byte_cnt, byte_cnt_org;
+ int count;
+ int i, j, k;
+ int data;
+ uint32_t filepos;
+
+ byte[2] = '\0';
+ j = 0;
+ filepos = 0;
+
+ while (NULL != fgets(line, MAX_BYTE_LENGTH, stream)) {
+ if (strlen(line) <= 1 || !isxdigit(line[0]))
+ continue;
+ else
+ break;
+ }
+
+ byte_cnt = strtol(line, NULL, 16);
+ byte_cnt_org = byte_cnt;
+
+ while (byte_cnt > MAX_BYTE_LENGTH) {
+
+ /* Handle case when the number of patch buffer is
+ * more than the 20K */
+ if (MAX_NUM_PATCH_ENTRY == patch_count) {
+ for (i = 0; i < patch_count; i++)
+ free(ram_patch[i].Data);
+ return -1;
+ }
+ ram_patch[patch_count].Len = MAX_BYTE_LENGTH;
+ ram_patch[patch_count].Data =
+ (uint8_t *) malloc(MAX_BYTE_LENGTH);
+
+ patch_count++;
+ byte_cnt = byte_cnt - MAX_BYTE_LENGTH;
+ }
+
+ ram_patch[patch_count].Len = (byte_cnt & 0xFF);
+
+ if (byte_cnt != 0) {
+ ram_patch[patch_count].Data = (uint8_t *) malloc(byte_cnt);
+ patch_count++;
+ }
+
+ count = 0;
+
+ while (byte_cnt_org > MAX_BYTE_LENGTH) {
+ for (i = 0, k = 0; i < MAX_BYTE_LENGTH * 2;
+ i += 2, k++, count += 2) {
+ if (fgets(byte, 2, stream) == NULL)
+ return -1;
+ data = strtoul(&byte[0], NULL, 16);
+ ram_patch[j].Data[k] = (data & 0xFF);
+ }
+
+ j++;
+ byte_cnt_org = byte_cnt_org - MAX_BYTE_LENGTH;
+ }
+
+ if (j == 0)
+ j++;
+
+ for (k = 0; k < byte_cnt_org; i += 2, k++, count += 2) {
+
+ if (fgets(byte, 2, stream) == NULL)
+ return -1;
+
+ data = strtoul(byte, NULL, 16);
+ ram_patch[j].Data[k] = (data & 0xFF);
+ }
+
+ return 0;
+}
+
+static int ath_parse_ps(FILE *stream)
+{
+ int status;
+ int i;
+ unsigned char bdaddr_present = 0;
+ status = -1;
+
+
+ if (NULL != stream)
+ status = ath_parse_file(stream);
+
+ if (tag_count == 0)
+ total_tag_len = 10;
+ else {
+
+ for (i = 0; i < tag_count; i++) {
+
+ if (ps_tag_entry[i].tag_id == 1)
+ bdaddr_present = 1;
+ if (ps_tag_entry[i].tag_len % 2 == 1)
+ total_tag_len = total_tag_len
+ + ps_tag_entry[i].tag_len + 1;
+ else
+ total_tag_len =
+ total_tag_len + ps_tag_entry[i].tag_len;
+
+ }
+ }
+ if (tag_count > 0 && !bdaddr_present)
+ total_tag_len = total_tag_len + 10;
+
+ total_tag_len = total_tag_len + 10 + (tag_count * 4);
+
+ return status;
+}
+
+static int ath_create_cmd_list(struct ps_cmd_packet **hci_packet_list,
+ uint32_t *num_packets)
+{
+ uint8_t count;
+ uint32_t num_cmd_entry = 0;
+ uint32_t crc = 0;
+
+ *num_packets = 0;
+
+ if (patch_count > 0)
+ crc |= RAM_PATCH_REGION;
+ if (tag_count > 0)
+ crc |= RAM_PS_REGION;
+
+ if (patch_count || tag_count) {
+
+ /* CRC Packet + PS Reset Packet + Patch List + PS List */
+ num_cmd_entry += (2 + patch_count + tag_count);
+ if (patch_count > 0)
+ num_cmd_entry++; /* Patch Enable Command */
+
+ (*hci_packet_list) =
+ malloc(sizeof(struct ps_cmd_packet) * num_cmd_entry);
+ if (NULL == *hci_packet_list)
+ perror("memory allocation failed \r\n");
+
+ ath_create_ps_command(PS_VERIFY_CRC, crc, *hci_packet_list,
+ num_packets);
+
+ if (patch_count > 0) {
+
+ ath_create_ps_command(WRITE_PATCH, patch_count,
+ *hci_packet_list, num_packets);
+ ath_create_ps_command(ENABLE_PATCH, 0,
+ *hci_packet_list,
+ num_packets);
+
+ }
+
+ ath_create_ps_command(PS_RESET, total_tag_len,
+ *hci_packet_list, num_packets);
+
+ if (tag_count > 0)
+ ath_create_ps_command(PS_WRITE, tag_count,
+ *hci_packet_list, num_packets);
+ }
+
+ for (count = 0; count < patch_count; count++)
+ free(ram_patch[patch_count].Data);
+
+ for (count = 0; count < tag_count; count++)
+ free(ps_tag_entry[count].tag_data);
+
+ return *num_packets;
+}
+
+static int ath_free_command_list(struct ps_cmd_packet **hci_packet_list,
+ uint32_t num_packets)
+{
+ int i;
+
+ if (*hci_packet_list == NULL)
+ return -1;
+
+ for (i = 0; i < num_packets; i++)
+ free((*hci_packet_list)[i].Hcipacket);
+
+ free(*hci_packet_list);
+
+ return 0;
+}
+
+static int wake_up_ar3k(int fd)
+{
+ struct termios ti;
+ int status;
+ int retrycount = 0;
+ if (tcgetattr(fd, &ti) < 0) {
+ perror("Can't get port settings");
+ return -1;
+ }
+ ioctl(fd, TIOCMGET, &status);
+ if (status & TIOCM_CTS)
+ return 0;
+
+ ti.c_cflag &= ~CRTSCTS;
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ perror("Can't set port settings");
+ return -1;
+ }
+
+ do {
+ ioctl(fd, TIOCMGET, &status);
+
+ /* deassert */
+ status &= (~TIOCM_RTS);
+ ioctl(fd, TIOCMSET, &status);
+
+ /* read */
+ ioctl(fd, TIOCMGET, &status);
+
+ /* assert */
+ status |= (TIOCM_RTS);
+ ioctl(fd, TIOCMSET, &status);
+ usleep(200);
+
+ /* read */
+ ioctl(fd, TIOCMGET, &status);
+ retrycount++;
+ if (retrycount > NUM_WAKEUP_RETRY)
+ break;
+ } while (!(status & TIOCM_CTS));
+ if (!(status & TIOCM_CTS))
+ return -1;
+
+ ti.c_cflag |= CRTSCTS;
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ perror("Can't set port settings");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * This API is used to send the HCI command to controller and return
+ * with a HCI Command Complete event.
+ */
+static int send_hci_cmd_wait_event(int dev,
+ uint8_t *hci_command,
+ int cmd_length,
+ uint8_t **event, uint8_t **buffer_to_free)
+{
+ int r;
+ uint8_t *hci_event;
+ uint8_t pkt_type = 0x01;
+
+ if (cmd_length == 0)
+ return -1;
+
+ /*
+ * Try to wake up the board if it is asleep
+ * The assumption here is that the board is asleep.
+ */
+ if (wake_up_ar3k(dev) < 0)
+ return -1;
+
+ if (write(dev, &pkt_type, 1) != 1)
+ return -1;
+
+ if (write(dev, (unsigned char *)hci_command, cmd_length) != cmd_length)
+ return -1;
+
+ hci_event = (uint8_t *) malloc(100);
+ r = read_hci_event(dev, (unsigned char *)hci_event, 100);
+ if (r > 0) {
+ *event = hci_event;
+ *buffer_to_free = hci_event;
+ } else {
+
+ /* Did not get an event from controller. return error */
+ free(hci_event);
+ *buffer_to_free = NULL;
+ return -1;
+ }
+ return 0;
+}
+
+static int read_ps_event(uint8_t *data)
+{
+
+ if (data[5] == 0xFC && data[6] == 0x00) {
+ switch (data[4]) {
+ case 0x0B:
+ return 0;
+ break;
+ case 0x0C:
+
+ /* Change Baudrate */
+ return 0;
+ break;
+ case 0x04:
+ return 0;
+ break;
+ case 0x1E:
+ rom_version = data[10];
+ rom_version = ((rom_version << 8) | data[9]);
+ rom_version = ((rom_version << 8) | data[8]);
+ rom_version = ((rom_version << 8) | data[7]);
+ build_version = data[14];
+ build_version = ((build_version << 8) | data[13]);
+ build_version = ((build_version << 8) | data[12]);
+ build_version = ((build_version << 8) | data[11]);
+ return 0;
+ break;
+ }
+ }
+ return -1;
+}
+
+static int get_ps_file_name(int devtype, char *path)
+{
+ char *filename;
+ int status = 0;
+
+ if (devtype == 0xdeadc0de) {
+ filename = PS_ASIC_FILE;
+ status = 1;
+ } else {
+ filename = PS_FPGA_FILE;
+ status = 0;
+ }
+
+ sprintf(path, "%s%s", FW_PATH, filename);
+ return status;
+}
+
+static int get_patch_file_name(int dev_type, int rom_version,
+ int build_version, char *path)
+{
+ if ((dev_type != 0) && (dev_type != 0xdeadc0de)
+ && (rom_version == 0x99999999) && (build_version == 1)) {
+ path[0] = '\0';
+ } else
+ sprintf(path, "%s%s", FW_PATH, PATCH_FILE);
+
+ return 0;
+}
+
+static int get_device_type(int dev, uint32_t *code)
+{
+ uint8_t hciCommand[] = {
+ 0x05, 0xfc, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04
+ };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ uint32_t reg;
+
+ int result = -1;
+ *code = 0;
+
+ hciCommand[3] = (uint8_t) (FPGA_REGISTER & 0xFF);
+ hciCommand[4] = (uint8_t) ((FPGA_REGISTER >> 8) & 0xFF);
+ hciCommand[5] = (uint8_t) ((FPGA_REGISTER >> 16) & 0xFF);
+ hciCommand[6] = (uint8_t) ((FPGA_REGISTER >> 24) & 0xFF);
+
+ if (send_hci_cmd_wait_event(dev, hciCommand,
+ sizeof(hciCommand), &event,
+ &buffer_to_free) == 0) {
+ if (event[5] == 0xFC && event[6] == 0x00) {
+
+ switch (event[4]) {
+
+ case 0x05:
+ reg = event[10];
+ reg = ((reg << 8) | event[9]);
+ reg = ((reg << 8) | event[8]);
+ reg = ((reg << 8) | event[7]);
+ *code = reg;
+ result = 0;
+ break;
+
+ case 0x06:
+ break;
+ }
+ }
+ }
+
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ return result;
+}
+
+static int read_ar3k_version(int pConfig)
+{
+ uint8_t hciCommand[] = {
+ 0x1E, 0xfc, 0x00
+ };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ int result = -1;
+
+ if (0 ==
+ send_hci_cmd_wait_event(pConfig, hciCommand,
+ sizeof(hciCommand), &event,
+ &buffer_to_free)) {
+ result = read_ps_event(event);
+ }
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ return result;
+}
+
+static int str2bdaddr(char *str_bdaddr, char *bdaddr)
+{
+ char bdbyte[3];
+ char *str_byte = str_bdaddr;
+ int i, j;
+ unsigned char colon_present = 0;
+
+ if (strstr(str_bdaddr, ":") != NULL)
+ colon_present = 1;
+
+ bdbyte[2] = '\0';
+
+ bdbyte[0] = str_byte[0];
+ bdbyte[1] = str_byte[1];
+
+ for (i = 0, j = 5; i < 6; i++, j--) {
+ bdaddr[j] = strtol(bdbyte, NULL, 16);
+
+ if (colon_present == 1)
+ str_byte += 3;
+ else
+ str_byte += 2;
+ }
+ return 0;
+}
+
+static int write_bdaddr(int pConfig, char *bdaddr)
+{
+ uint8_t bdaddr_cmd[] = { 0x0B, 0xFC, 0x0A, 0x01, 0x01,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ int result = -1;
+
+ str2bdaddr(bdaddr, (char *)&bdaddr_cmd[7]);
+
+ if (0 == send_hci_cmd_wait_event(pConfig, bdaddr_cmd,
+ sizeof(bdaddr_cmd),
+ &event, &buffer_to_free)) {
+
+ if (event[5] == 0xFC && event[6] == 0x00) {
+ if (event[4] == 0x0B)
+ result = 0;
+ }
+
+ } else
+ perror(" Write failed \n");
+
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ return result;
+}
+
+int ath_ps_download(int hdev)
+{
+ int i;
+ int status;
+ struct ps_cmd_packet *hci_cmd_list; /* List storing the commands */
+ uint32_t numCmds;
+ uint8_t *event;
+ uint8_t *buffer_to_free;
+ uint32_t DevType;
+ char patchFileName[PATH_MAX];
+ char PsFileName[PATH_MAX];
+ char bdaddr_file_name[PATH_MAX];
+ FILE *stream;
+ char bdaddr[21];
+
+ status = 0;
+ hci_cmd_list = NULL;
+
+ /* First verify if the controller is an FPGA or ASIC,
+ *so depending on the device type the PS file to be written
+ * will be different.
+ */
+ do {
+ if (get_device_type(hdev, &DevType) == -1) {
+ status = -1;
+ break;
+ }
+ if (read_ar3k_version(hdev) == -1) {
+ status = -1;
+ break;
+ }
+
+ get_ps_file_name(DevType, PsFileName);
+ get_patch_file_name(DevType, rom_version, build_version,
+ patchFileName);
+
+ /* Read the PS file to a dynamically allocated buffer */
+ stream = fopen(PsFileName, "r");
+ if (stream == NULL) {
+ perror("firmware file open error\n");
+ status = -1;
+ break;
+ }
+ status = ath_parse_ps(stream);
+ fclose(stream);
+
+ /*
+ * It is not necessary that Patch file be available,
+ * continue with PS Operations if.
+ * failed.
+ */
+ if (patchFileName[0] == '\0')
+ status = 0;
+ stream = fopen(patchFileName, "r");
+ if (stream == NULL)
+ status = 0;
+ else {
+ /* parse and store the Patch file contents to
+ * a global variables
+ */
+ status = parse_patch_file(stream);
+ fclose(stream);
+ }
+
+ /* Create an HCI command list
+ * from the parsed PS and patch information */
+ ath_create_cmd_list(&hci_cmd_list, &numCmds);
+
+ /*
+ * First Send the CRC packet,
+ * We have to continue with the PS operations
+ * only if the CRC packet has been replied with
+ * a Command complete event with status Error.
+ */
+ if (send_hci_cmd_wait_event
+ (hdev, hci_cmd_list[0].Hcipacket, hci_cmd_list[0].packetLen,
+ &event, &buffer_to_free) == 0) {
+
+ if (read_ps_event(event) == 0) {
+
+ /* Exit if the status is success */
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ status = 0;
+ break;
+ }
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+ } else {
+ status = -1;
+ break;
+ }
+ for (i = 1; i < numCmds; i++) {
+
+ if (send_hci_cmd_wait_event
+ (hdev, hci_cmd_list[i].Hcipacket,
+ hci_cmd_list[i].packetLen, &event,
+ &buffer_to_free) == 0) {
+
+ if (read_ps_event(event) < 0) {
+
+ /* Exit if the status is not success */
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ status = -1;
+ break;
+ }
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+ } else {
+ status = 0;
+ break;
+ }
+ }
+ /* Read the PS file to a dynamically allocated buffer */
+ sprintf(bdaddr_file_name, "%s%s", FW_PATH, BDADDR_FILE);
+ stream = fopen(bdaddr_file_name, "r");
+
+ if (stream == NULL) {
+ status = 0;
+ break;
+ }
+
+ if (fgets(bdaddr, 20, stream) != NULL)
+ status = write_bdaddr(hdev, bdaddr);
+
+ fclose(stream);
+
+ } while (FALSE);
+
+ if (hci_cmd_list != NULL)
+ ath_free_command_list(&hci_cmd_list, numCmds);
+
+ return status;
+}
--
1.7.0
^ permalink raw reply related
* [PATCH 4/4] Add options to test MaxTx and TxWindow
From: Gustavo F. Padovan @ 2010-03-30 18:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo
In-Reply-To: <1269975209-10044-3-git-send-email-padovan@profusion.mobi>
---
test/l2test.c | 22 +++++++++++++++++++++-
1 files changed, 21 insertions(+), 1 deletions(-)
diff --git a/test/l2test.c b/test/l2test.c
index d11992f..9413070 100644
--- a/test/l2test.c
+++ b/test/l2test.c
@@ -75,6 +75,12 @@ static int omtu = 0;
/* Default FCS option */
static int fcs = 0x01;
+/* Default Transmission Window */
+static int txwin_size = 63;
+
+/* Default Max Transmission */
+static int max_transmit = 3;
+
/* Default data size */
static long data_size = -1;
static long buffer_size = 2048;
@@ -226,6 +232,8 @@ static int do_connect(char *svr)
opts.mode = rfcmode;
opts.fcs = fcs;
+ opts.txwin_size = txwin_size;
+ opts.max_tx = max_transmit;
if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)",
@@ -388,6 +396,8 @@ static void do_listen(void (*handler)(int sk))
opts.mode = rfcmode;
opts.fcs = fcs;
+ opts.txwin_size = txwin_size;
+ opts.max_tx = max_transmit;
if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)",
@@ -1064,6 +1074,8 @@ static void usage(void)
"\t[-D milliseconds] delay after sending num frames (default = 0)\n"
"\t[-X mode] select retransmission/flow-control mode\n"
"\t[-F fcs] use CRC16 check (default = 1)\n"
+ "\t[-Q num] Max Transmit value (default = 3)\n"
+ "\t[-Z size] Transmission Window size (default = 63)\n"
"\t[-R] reliable mode\n"
"\t[-G] use connectionless channel (datagram)\n"
"\t[-U] use sock stream\n"
@@ -1081,7 +1093,7 @@ int main(int argc, char *argv[])
bacpy(&bdaddr, BDADDR_ANY);
- while ((opt=getopt(argc,argv,"rdscuwmntqxyzpb:i:P:I:O:B:N:L:W:C:D:X:F:RUGAESMT")) != EOF) {
+ while ((opt=getopt(argc,argv,"rdscuwmntqxyzpb:i:P:I:O:B:N:L:W:C:D:X:F:Q:Z:RUGAESMT")) != EOF) {
switch(opt) {
case 'r':
mode = RECV;
@@ -1237,6 +1249,14 @@ int main(int argc, char *argv[])
timestamp = 1;
break;
+ case 'Q':
+ max_transmit = atoi(optarg);
+ break;
+
+ case 'Z':
+ txwin_size = atoi(optarg);
+ break;
+
default:
usage();
exit(1);
--
1.6.4.4
^ permalink raw reply related
* [PATCH 3/4] Add txWindow and MaxTt to l2cap_options
From: Gustavo F. Padovan @ 2010-03-30 18:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo
In-Reply-To: <1269975209-10044-2-git-send-email-padovan@profusion.mobi>
---
lib/l2cap.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/lib/l2cap.h b/lib/l2cap.h
index 648615d..e59cfdd 100644
--- a/lib/l2cap.h
+++ b/lib/l2cap.h
@@ -52,6 +52,8 @@ struct l2cap_options {
uint16_t flush_to;
uint8_t mode;
uint8_t fcs;
+ uint8_t max_tx;
+ uint16_t txwin_size;
};
#define L2CAP_CONNINFO 0x02
--
1.6.4.4
^ permalink raw reply related
* [PATCH 2/4] Add duplex test case to l2test
From: Gustavo F. Padovan @ 2010-03-30 18:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo
In-Reply-To: <1269975209-10044-1-git-send-email-padovan@profusion.mobi>
Use a SOCK_NONBLOCK to send and receive at the same time.
---
test/l2test.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 42 insertions(+), 1 deletions(-)
diff --git a/test/l2test.c b/test/l2test.c
index bfffab2..d11992f 100644
--- a/test/l2test.c
+++ b/test/l2test.c
@@ -60,6 +60,8 @@ enum {
LSEND,
SENDDUMP,
LSENDDUMP,
+ LSENDRECV,
+ CSENDRECV,
INFOREQ,
PAIRING,
};
@@ -775,6 +777,22 @@ static void senddump_mode(int sk)
dump_mode(sk);
}
+static void send_and_recv_mode(int sk)
+{
+ int flags;
+
+ if ((flags = fcntl(sk, F_GETFL, 0)) < 0)
+ flags = 0;
+ fcntl(sk, F_SETFL, flags | O_NONBLOCK);
+
+ /* fork for duplex channel */
+ if (fork())
+ send_mode(sk);
+ else
+ recv_mode(sk);
+ return;
+}
+
static void reconnect_mode(char *svr)
{
while (1) {
@@ -1024,6 +1042,8 @@ static void usage(void)
"\t-w listen and send\n"
"\t-d listen and dump incoming data\n"
"\t-x listen, then send, then dump incoming data\n"
+ "\t-t listen, then send and receive at the same time\n"
+ "\t-q connect, then send and receive at the same time\n"
"\t-s connect and send\n"
"\t-u connect and receive\n"
"\t-n connect and be silent\n"
@@ -1061,7 +1081,7 @@ int main(int argc, char *argv[])
bacpy(&bdaddr, BDADDR_ANY);
- while ((opt=getopt(argc,argv,"rdscuwmnxyzpb:i:P:I:O:B:N:L:W:C:D:X:F:RGUAESMT")) != EOF) {
+ while ((opt=getopt(argc,argv,"rdscuwmntqxyzpb:i:P:I:O:B:N:L:W:C:D:X:F:RUGAESMT")) != EOF) {
switch(opt) {
case 'r':
mode = RECV;
@@ -1100,6 +1120,15 @@ int main(int argc, char *argv[])
need_addr = 1;
break;
+ case 't':
+ mode = LSENDRECV;
+ break;
+
+ case 'q':
+ mode = CSENDRECV;
+ need_addr = 1;
+ break;
+
case 'x':
mode = LSENDDUMP;
break;
@@ -1286,6 +1315,18 @@ int main(int argc, char *argv[])
do_listen(senddump_mode);
break;
+ case LSENDRECV:
+ do_listen(send_and_recv_mode);
+ break;
+
+ case CSENDRECV:
+ sk = do_connect(argv[optind]);
+ if (sk < 0)
+ exit(1);
+
+ send_and_recv_mode(sk);
+ break;
+
case INFOREQ:
info_request(argv[optind]);
exit(0);
--
1.6.4.4
^ permalink raw reply related
* [PATCH 1/4] l2test: add option to use SOCK_STREAM
From: Gustavo F. Padovan @ 2010-03-30 18:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo
---
test/l2test.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/test/l2test.c b/test/l2test.c
index 714604a..bfffab2 100644
--- a/test/l2test.c
+++ b/test/l2test.c
@@ -1046,6 +1046,7 @@ static void usage(void)
"\t[-F fcs] use CRC16 check (default = 1)\n"
"\t[-R] reliable mode\n"
"\t[-G] use connectionless channel (datagram)\n"
+ "\t[-U] use sock stream\n"
"\t[-A] request authentication\n"
"\t[-E] request encryption\n"
"\t[-S] secure connection\n"
@@ -1060,7 +1061,7 @@ int main(int argc, char *argv[])
bacpy(&bdaddr, BDADDR_ANY);
- while ((opt=getopt(argc,argv,"rdscuwmnxyzpb:i:P:I:O:B:N:L:W:C:D:X:F:RGAESMT")) != EOF) {
+ while ((opt=getopt(argc,argv,"rdscuwmnxyzpb:i:P:I:O:B:N:L:W:C:D:X:F:RGUAESMT")) != EOF) {
switch(opt) {
case 'r':
mode = RECV;
@@ -1199,6 +1200,10 @@ int main(int argc, char *argv[])
socktype = SOCK_DGRAM;
break;
+ case 'U':
+ socktype = SOCK_STREAM;
+ break;
+
case 'T':
timestamp = 1;
break;
--
1.6.4.4
^ permalink raw reply related
* [PATCH 10/10] Bluetooth: Enable option to configure Max Transmission value via sockopt
From: Gustavo F. Padovan @ 2010-03-30 18:52 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1269975160-9994-9-git-send-email-padovan@profusion.mobi>
With the sockopt extension we can set a per-channel MaxTx value.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 2 ++
net/bluetooth/l2cap.c | 7 ++++++-
2 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 44dd961..15f6e55 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -55,6 +55,7 @@ struct l2cap_options {
__u16 flush_to;
__u8 mode;
__u8 fcs;
+ __u8 max_tx;
__u16 txwin_size;
};
@@ -340,6 +341,7 @@ struct l2cap_pinfo {
__u8 ident;
__u8 tx_win;
+ __u8 max_tx;
__u8 remote_tx_win;
__u8 remote_max_tx;
__u16 retrans_timeout;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 32824b9..d5a34a5 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -783,6 +783,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->omtu = l2cap_pi(parent)->omtu;
pi->mode = l2cap_pi(parent)->mode;
pi->fcs = l2cap_pi(parent)->fcs;
+ pi->max_tx = l2cap_pi(parent)->max_tx;
pi->tx_win = l2cap_pi(parent)->tx_win;
pi->sec_level = l2cap_pi(parent)->sec_level;
pi->role_switch = l2cap_pi(parent)->role_switch;
@@ -791,6 +792,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->imtu = L2CAP_DEFAULT_MTU;
pi->omtu = 0;
pi->mode = L2CAP_MODE_BASIC;
+ pi->max_tx = max_transmit;
pi->fcs = L2CAP_FCS_CRC16;
pi->tx_win = tx_window;
pi->sec_level = BT_SECURITY_LOW;
@@ -1781,6 +1783,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);
@@ -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)->max_tx = opts.max_tx;
l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size;
break;
@@ -1908,6 +1912,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));
@@ -2327,7 +2332,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);
--
1.6.4.4
^ permalink raw reply related
* [PATCH 09/10] Bluetooth: Add module parameter for txWindow size on L2CAP
From: Gustavo F. Padovan @ 2010-03-30 18:52 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1269975160-9994-8-git-send-email-padovan@profusion.mobi>
Very useful for testing purposes.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
[jprvita@profusion.mobi: improved parameter description]
Signed-off-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 8a6d073..32824b9 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -57,6 +57,7 @@
static int enable_ertm = 0;
static int max_transmit = L2CAP_DEFAULT_MAX_TX;
+static int tx_window = L2CAP_DEFAULT_TX_WINDOW;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
static u8 l2cap_fixed_chan[8] = { 0x02, };
@@ -791,7 +792,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->omtu = 0;
pi->mode = L2CAP_MODE_BASIC;
pi->fcs = L2CAP_FCS_CRC16;
- pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
+ pi->tx_win = tx_window;
pi->sec_level = BT_SECURITY_LOW;
pi->role_switch = 0;
pi->force_reliable = 0;
@@ -4301,6 +4302,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 <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
MODULE_VERSION(VERSION);
--
1.6.4.4
^ permalink raw reply related
* [PATCH 08/10] Bluetooth: Change acknowledgement to use the value of txWindow
From: Gustavo F. Padovan @ 2010-03-30 18:52 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1269975160-9994-7-git-send-email-padovan@profusion.mobi>
Now that we can set the txWindow we need to change the acknowledgement
procedure to ack after each (pi->txWindow/6 + 1). The plus 1 is to avoid
the zero value.
It also renames pi->num_to_ack to a better name: pi->num_acked.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 3 +--
net/bluetooth/l2cap.c | 7 ++++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index fdbe8ee..44dd961 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -30,7 +30,6 @@
#define L2CAP_DEFAULT_MIN_MTU 48
#define L2CAP_DEFAULT_FLUSH_TO 0xffff
#define L2CAP_DEFAULT_TX_WINDOW 63
-#define L2CAP_DEFAULT_NUM_TO_ACK (L2CAP_DEFAULT_TX_WINDOW/5)
#define L2CAP_DEFAULT_MAX_TX 3
#define L2CAP_DEFAULT_RETRANS_TO 1000 /* 1 second */
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
@@ -333,7 +332,7 @@ struct l2cap_pinfo {
__u8 frames_sent;
__u8 unacked_frames;
__u8 retry_count;
- __u8 num_to_ack;
+ __u8 num_acked;
__u16 sdu_len;
__u16 partial_sdu_len;
struct sk_buff *sdu;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 79c9ac7..8a6d073 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2250,7 +2250,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,
@@ -3463,6 +3463,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);
@@ -3557,8 +3558,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;
--
1.6.4.4
^ permalink raw reply related
* [PATCH 07/10] Bluetooth: Add sockopt configuration for txWindow on L2CAP
From: Gustavo F. Padovan @ 2010-03-30 18:52 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1269975160-9994-6-git-send-email-padovan@profusion.mobi>
Now can set/get Transmission Window size via sockopt.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 2 ++
net/bluetooth/l2cap.c | 7 ++++++-
2 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 0f4e423..fdbe8ee 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -56,6 +56,7 @@ struct l2cap_options {
__u16 flush_to;
__u8 mode;
__u8 fcs;
+ __u16 txwin_size;
};
#define L2CAP_CONNINFO 0x02
@@ -339,6 +340,7 @@ struct l2cap_pinfo {
__u8 ident;
+ __u8 tx_win;
__u8 remote_tx_win;
__u8 remote_max_tx;
__u16 retrans_timeout;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 4580fcf..79c9ac7 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -782,6 +782,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->omtu = l2cap_pi(parent)->omtu;
pi->mode = l2cap_pi(parent)->mode;
pi->fcs = l2cap_pi(parent)->fcs;
+ pi->tx_win = l2cap_pi(parent)->tx_win;
pi->sec_level = l2cap_pi(parent)->sec_level;
pi->role_switch = l2cap_pi(parent)->role_switch;
pi->force_reliable = l2cap_pi(parent)->force_reliable;
@@ -790,6 +791,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
pi->omtu = 0;
pi->mode = L2CAP_MODE_BASIC;
pi->fcs = L2CAP_FCS_CRC16;
+ pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
pi->sec_level = BT_SECURITY_LOW;
pi->role_switch = 0;
pi->force_reliable = 0;
@@ -1778,6 +1780,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)) {
@@ -1789,6 +1792,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:
@@ -1903,6 +1907,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))
@@ -2320,7 +2325,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;
--
1.6.4.4
^ permalink raw reply related
* [PATCH 06/10] Bluetooth: Send Ack after clear the SREJ list
From: Gustavo F. Padovan @ 2010-03-30 18:52 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1269975160-9994-5-git-send-email-padovan@profusion.mobi>
As specified by Bluetooth 3.0 spec we shall send an acknowledgment using
the Send-Ack() after clear the SREJ list.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 6196f2c..4580fcf 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3497,6 +3497,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;
--
1.6.4.4
^ permalink raw reply related
* [PATCH 05/10] Bluetooth: Check the SDU size against the MTU value
From: Gustavo F. Padovan @ 2010-03-30 18:52 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1269975160-9994-4-git-send-email-padovan@profusion.mobi>
If the SDU size is greater than the MTU something is wrong, so report
an error.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
[jprvita@profusion.mobi: set err to appropriate errno value]
Signed-off-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index e6e2351..6196f2c 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3335,6 +3335,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;
--
1.6.4.4
^ permalink raw reply related
* [PATCH 04/10] Bluetooth: Add le16 macro to Retransmission and Monitor Timeouts values
From: Gustavo F. Padovan @ 2010-03-30 18:52 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1269975160-9994-3-git-send-email-padovan@profusion.mobi>
Fix a possible problem with Big Endian machines.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
net/bluetooth/l2cap.c | 14 ++++++++------
1 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 4c98e3c..e6e2351 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2483,8 +2483,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;
@@ -2574,8 +2576,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:
@@ -2630,8 +2632,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:
--
1.6.4.4
^ permalink raw reply related
* [PATCH 03/10] Bluetooth: Fix configuration of the MPS value
From: Gustavo F. Padovan @ 2010-03-30 18:52 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, gustavo, jprvita
In-Reply-To: <1269975160-9994-2-git-send-email-padovan@profusion.mobi>
We were accepting values bigger than we can accept. This was leading
ERTM to drop packets because of wrong FCS checks.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
---
include/net/bluetooth/l2cap.h | 3 ++-
net/bluetooth/l2cap.c | 36 ++++++++++++++++++++----------------
2 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 48f10f4..0f4e423 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -343,7 +343,8 @@ struct l2cap_pinfo {
__u8 remote_max_tx;
__u16 retrans_timeout;
__u16 monitor_timeout;
- __u16 max_pdu_size;
+ __u16 remote_mps;
+ __u16 mps;
__le16 sport;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 40aff8d..4c98e3c 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1605,21 +1605,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;
@@ -1697,7 +1697,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)) {
@@ -2326,7 +2326,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);
@@ -2349,7 +2349,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);
@@ -2478,7 +2478,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;
@@ -2491,7 +2494,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;
@@ -2570,11 +2576,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);
}
}
@@ -3758,7 +3763,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))
@@ -3789,8 +3794,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))
--
1.6.4.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox