[PATCH 05/10] fixed seqno issues

From: Mark P . Mendelsohn
Date: Mon Aug 22 2011 - 14:42:10 EST


---
drivers/bluetooth/hci_h5.c | 113 +++++++++++---------------------------------
1 files changed, 28 insertions(+), 85 deletions(-)

diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index 265a9c5..88ad715 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -61,10 +61,6 @@ static int h5extn = 1;
#define H5_ACK_PKT 0x00
#define H5_LE_PKT 0x0f

-static u8 h5_wakeup_msg[] = { 0x05, 0xfa };
-static u8 h5_woken_msg[] = { 0x06, 0xf9 };
-static u8 h5_sleep_msg[] = { 0x07, 0x78 };
-
struct h5_struct {
struct sk_buff_head unack; /* Unack'ed packets queue */
struct sk_buff_head rel; /* Reliable packets queue */
@@ -96,53 +92,8 @@ struct h5_struct {

/* Reliable packet sequence number - used to assign seq to each rel pkt. */
u8 msgq_txseq;
-
- u8 sleep_state;
- u8 is_there_activity;
- u16 inactive_period;
-};
-
-enum sleep_states {
- H5_ASLEEP,
- H5_ASLEEP_TO_AWAKE,
- H5_AWAKE,
- H5_AWAKE_TO_ASLEEP
};

-#define TIMER_PERIOD 100
-#define HOST_CONTROLLER_IDLE_THRSH 4000
-
-static struct timer_list sleep_timer;
-
-extern struct sk_buff *h5_prepare_pkt(struct h5_struct *h5, u8 *data,
- int len, int pkt_type);
-
-//
-// Timeout Handler
-//
-
-void sleep_timer_function(unsigned long data)
-{
- struct h5_struct *lh5 = (struct h5_struct *)data;
-
- if (lh5->is_there_activity) {
- lh5->is_there_activity = 0;
- lh5->inactive_period = 0;
- } else if (lh5->sleep_state != H5_ASLEEP) {
- lh5->inactive_period += TIMER_PERIOD;
-
- if (lh5->inactive_period >= HOST_CONTROLLER_IDLE_THRSH) {
- BT_DBG("moves to ASLEEP");
- lh5->sleep_state = H5_ASLEEP;
- lh5->inactive_period = 0;
- struct sk_buff *nskb = h5_prepare_pkt(lh5, h5_sleep_msg, sizeof(h5_sleep_msg), 15);
- skb_queue_tail(&lh5->unrel, nskb);
- }
- }
-
- mod_timer(&sleep_timer, jiffies + TIMER_PERIOD * HZ / 1000);
-}
-
/* ---- H5 CRC calculation ---- */

/* Table for calculating CRC for polynomial 0x1021, LSB processed first,
@@ -219,14 +170,6 @@ static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
return 0;
}

- h5->is_there_activity = 1;
-
- if (h5->sleep_state == H5_ASLEEP) {
- struct sk_buff *nskb = h5_prepare_pkt(h5, h5_wakeup_msg, sizeof(h5_wakeup_msg), 15);
- skb_queue_tail(&h5->unrel, skb);
- h5->sleep_state = H5_AWAKE;
- }
-
switch (bt_cb(skb)->pkt_type) {
case HCI_ACLDATA_PKT:
case HCI_COMMAND_PKT:
@@ -246,7 +189,7 @@ static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
return 0;
}

-struct sk_buff *h5_prepare_pkt(struct h5_struct *h5, u8 *data,
+static struct sk_buff *h5_prepare_pkt(struct h5_struct *h5, u8 *data,
int len, int pkt_type)
{
struct sk_buff *nskb;
@@ -315,6 +258,7 @@ struct sk_buff *h5_prepare_pkt(struct h5_struct *h5, u8 *data,
if (rel) {
hdr[0] |= 0x80 + h5->msgq_txseq;
BT_DBG("Sending packet with seqno %u\n", h5->msgq_txseq);
+ h5->msgq_txseq = (h5->msgq_txseq + 1) & 0x07;
}

if (h5->use_crc)
@@ -414,7 +358,6 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu)
static int h5_flush(struct hci_uart *hu)
{
BT_DBG("hu %p\n", hu);
- del_timer_sync(&sleep_timer);
return 0;
}

@@ -430,20 +373,23 @@ static void h5_pkt_cull(struct h5_struct *h5)

pkts_to_be_removed = skb_queue_len(&h5->unack);

+ printk("%s: unack len %d\n", pkts_to_be_removed);
+
seqno = h5->msgq_txseq;

while (pkts_to_be_removed) {
- if (((h5->rxack - 1) & 0x07) == seqno)
+ printk("ack %d seq %d\n", h5->rxack, seqno);
+ if (h5->rxack == seqno)
break;

pkts_to_be_removed--;
- seqno = (seqno + 1) & 0x07;
+ seqno = (seqno - 1) & 0x07;
}

-/*
+ printk("seqno now %d\n", seqno);
+
if (h5->rxack != seqno)
BT_ERR("Peer acked invalid packet");
-*/

BT_DBG("Removing %u pkts out of %u, up to seqno %u\n",
pkts_to_be_removed, skb_queue_len(&h5->unack),
@@ -475,22 +421,28 @@ static void h5_pkt_cull(struct h5_struct *h5)
static void h5_handle_le_pkt(struct hci_uart *hu)
{
struct h5_struct *h5 = hu->priv;
- u8 wakeup_pkt[] = { 0x05, 0xfa };
- u8 woken_pkt[] = { 0x06, 0xf9 };
-
- struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
-
- BT_DBG("Found a LE pkt\n");
-
- if (!nskb)
- return;
-
- if (!memcmp(&h5->rx_skb->data[4], wakeup_pkt, 2)) {
- memcpy(skb_put(nskb, 2), woken_pkt, 2);
+ u8 conf_pkt[4] = { 0xad, 0xef, 0xac, 0xed };
+ u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 };
+ u8 sync_pkt[4] = { 0x00, 0xd0, 0x01, 0x7e };
+
+ /* spot "conf" pkts and reply with a "conf rsp" pkt */
+ if (h5->rx_skb->data[1] >> 4 == 4 && h5->rx_skb->data[2] == 0 &&
+ !memcmp(&h5->rx_skb->data[4], conf_pkt, 4)) {
+ struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
+
+ BT_DBG("Found a LE conf pkt\n");
+ if (!nskb)
+ return;
+ memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
bt_cb(nskb)->pkt_type = H5_LE_PKT;
+
skb_queue_head(&h5->unrel, nskb);
hci_uart_tx_wakeup(hu);
- } else if (!memcmp(&h5->rx_skb->data[4], woken_pkt, 2)) {
+ }
+ /* Spot "sync" pkts. If we find one...disaster! */
+ else if (h5->rx_skb->data[1] >> 4 == 4 && h5->rx_skb->data[2] == 0 &&
+ !memcmp(&h5->rx_skb->data[4], sync_pkt, 4)) {
+ BT_ERR("Found a LE sync pkt, card has reset");
}
}

@@ -824,15 +776,6 @@ static int h5_open(struct hci_uart *hu)
if (h5txcrc)
h5->use_crc = 1;

- init_timer(&sleep_timer);
-
- sleep_timer.expires = jiffies + TIMER_PERIOD * HZ / 1000;
- sleep_timer.data = (unsigned long)h5;
- sleep_timer.function = sleep_timer_function;
-
- add_timer(&sleep_timer);
- h5->is_there_activity = 0;
-
return 0;
}

--
1.7.1