aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2012-07-16 09:12:08 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-07-17 13:48:24 -0400
commit43eb12d7896063d06011baab7097944a70c7e45a (patch)
tree36f01a58e8621517fa2051a577547ca33cdfb518
parent01977c0bbbc834e57436be0bab31c3df11d61710 (diff)
Bluetooth: Fix/implement Three-wire reliable packet sending
This patch should complete the necessary code for sending reliable Three-wire packets. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
-rw-r--r--drivers/bluetooth/hci_h5.c87
1 files changed, 70 insertions, 17 deletions
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index f50afb2fb36..6c7b27e921a 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -64,15 +64,15 @@ struct h5 {
64 struct sk_buff *rx_skb; /* Receive buffer */ 64 struct sk_buff *rx_skb; /* Receive buffer */
65 size_t rx_pending; /* Expecting more bytes */ 65 size_t rx_pending; /* Expecting more bytes */
66 bool rx_esc; /* SLIP escape mode */ 66 bool rx_esc; /* SLIP escape mode */
67 u8 rx_ack; /* Last ack number received */
68 u8 rx_seq; /* Last seq number received */
67 69
68 int (*rx_func) (struct hci_uart *hu, u8 c); 70 int (*rx_func) (struct hci_uart *hu, u8 c);
69 71
70 struct timer_list timer; /* Retransmission timer */ 72 struct timer_list timer; /* Retransmission timer */
71 73
72 bool txack_req; 74 bool tx_ack_req; /* Pending ack to send */
73 75 u8 tx_seq; /* Next seq number to send */
74 u8 next_ack;
75 u8 next_seq;
76}; 76};
77 77
78static void h5_reset_rx(struct h5 *h5); 78static void h5_reset_rx(struct h5 *h5);
@@ -89,7 +89,7 @@ static void h5_timed_event(unsigned long arg)
89 spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); 89 spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING);
90 90
91 while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) { 91 while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) {
92 h5->next_seq = (h5->next_seq - 1) & 0x07; 92 h5->tx_seq = (h5->tx_seq - 1) & 0x07;
93 skb_queue_head(&h5->rel, skb); 93 skb_queue_head(&h5->rel, skb);
94 } 94 }
95 95
@@ -138,6 +138,45 @@ static int h5_close(struct hci_uart *hu)
138 return 0; 138 return 0;
139} 139}
140 140
141static void h5_pkt_cull(struct h5 *h5)
142{
143 struct sk_buff *skb, *tmp;
144 unsigned long flags;
145 int i, to_remove;
146 u8 seq;
147
148 spin_lock_irqsave(&h5->unack.lock, flags);
149
150 to_remove = skb_queue_len(&h5->unack);
151
152 seq = h5->tx_seq;
153
154 while (to_remove > 0) {
155 if (h5->rx_ack == seq)
156 break;
157
158 to_remove--;
159 seq = (seq - 1) % 8;
160 }
161
162 if (seq != h5->rx_ack)
163 BT_ERR("Controller acked invalid packet");
164
165 i = 0;
166 skb_queue_walk_safe(&h5->unack, skb, tmp) {
167 if (i++ >= to_remove)
168 break;
169
170 __skb_unlink(skb, &h5->unack);
171 kfree_skb(skb);
172 }
173
174 if (skb_queue_empty(&h5->unack))
175 del_timer(&h5->timer);
176
177 spin_unlock_irqrestore(&h5->unack.lock, flags);
178}
179
141static void h5_handle_internal_rx(struct hci_uart *hu) 180static void h5_handle_internal_rx(struct hci_uart *hu)
142{ 181{
143 BT_DBG("%s", hu->hdev->name); 182 BT_DBG("%s", hu->hdev->name);
@@ -146,17 +185,24 @@ static void h5_handle_internal_rx(struct hci_uart *hu)
146static void h5_complete_rx_pkt(struct hci_uart *hu) 185static void h5_complete_rx_pkt(struct hci_uart *hu)
147{ 186{
148 struct h5 *h5 = hu->priv; 187 struct h5 *h5 = hu->priv;
149 u8 pkt_type; 188 const unsigned char *hdr = h5->rx_skb->data;
150 189
151 BT_DBG("%s", hu->hdev->name); 190 BT_DBG("%s", hu->hdev->name);
152 191
153 pkt_type = h5->rx_skb->data[1] & 0x0f; 192 if (H5_HDR_RELIABLE(hdr)) {
193 h5->tx_seq = (h5->tx_seq + 1) % 8;
194 h5->tx_ack_req = true;
195 }
154 196
155 switch (pkt_type) { 197 h5->rx_ack = H5_HDR_ACK(hdr);
198
199 h5_pkt_cull(h5);
200
201 switch (H5_HDR_PKT_TYPE(hdr)) {
156 case HCI_EVENT_PKT: 202 case HCI_EVENT_PKT:
157 case HCI_ACLDATA_PKT: 203 case HCI_ACLDATA_PKT:
158 case HCI_SCODATA_PKT: 204 case HCI_SCODATA_PKT:
159 bt_cb(h5->rx_skb)->pkt_type = pkt_type; 205 bt_cb(h5->rx_skb)->pkt_type = H5_HDR_PKT_TYPE(hdr);
160 206
161 /* Remove Three-wire header */ 207 /* Remove Three-wire header */
162 skb_pull(h5->rx_skb, 4); 208 skb_pull(h5->rx_skb, 4);
@@ -193,7 +239,7 @@ static int h5_rx_payload(struct hci_uart *hu, unsigned char c)
193 239
194 BT_DBG("%s 0x%02hhx", hu->hdev->name, c); 240 BT_DBG("%s 0x%02hhx", hu->hdev->name, c);
195 241
196 if ((hdr[0] >> 4) & 0x01) { 242 if (H5_HDR_CRC(hdr)) {
197 h5->rx_func = h5_rx_crc; 243 h5->rx_func = h5_rx_crc;
198 h5->rx_pending = 2; 244 h5->rx_pending = 2;
199 } else { 245 } else {
@@ -217,8 +263,15 @@ static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c)
217 return 0; 263 return 0;
218 } 264 }
219 265
266 if (H5_HDR_RELIABLE(hdr) && H5_HDR_SEQ(hdr) != h5->tx_seq) {
267 BT_ERR("Out-of-order packet arrived (%u != %u)",
268 H5_HDR_SEQ(hdr), h5->tx_seq);
269 h5_reset_rx(h5);
270 return 0;
271 }
272
220 h5->rx_func = h5_rx_payload; 273 h5->rx_func = h5_rx_payload;
221 h5->rx_pending = ((hdr[1] >> 4) & 0xff) + (hdr[2] << 4); 274 h5->rx_pending = H5_HDR_LEN(hdr);
222 275
223 return 0; 276 return 0;
224} 277}
@@ -412,13 +465,13 @@ static struct sk_buff *h5_build_pkt(struct h5 *h5, bool rel, u8 pkt_type,
412 465
413 h5_slip_delim(nskb); 466 h5_slip_delim(nskb);
414 467
415 hdr[0] = h5->next_ack << 3; 468 hdr[0] = h5->rx_seq << 3;
416 h5->txack_req = false; 469 h5->tx_ack_req = false;
417 470
418 if (rel) { 471 if (rel) {
419 hdr[0] |= 1 << 7; 472 hdr[0] |= 1 << 7;
420 hdr[0] |= h5->next_seq; 473 hdr[0] |= h5->tx_seq;
421 h5->next_seq = (h5->next_seq + 1) % 8; 474 h5->tx_seq = (h5->tx_seq + 1) % 8;
422 } 475 }
423 476
424 hdr[1] = pkt_type | ((len & 0x0f) << 4); 477 hdr[1] = pkt_type | ((len & 0x0f) << 4);
@@ -461,7 +514,7 @@ static struct sk_buff *h5_prepare_pkt(struct h5 *h5, u8 pkt_type,
461 514
462static struct sk_buff *h5_prepare_ack(struct h5 *h5) 515static struct sk_buff *h5_prepare_ack(struct h5 *h5)
463{ 516{
464 h5->txack_req = false; 517 h5->tx_ack_req = false;
465 return NULL; 518 return NULL;
466} 519}
467 520
@@ -505,7 +558,7 @@ static struct sk_buff *h5_dequeue(struct hci_uart *hu)
505unlock: 558unlock:
506 spin_unlock_irqrestore(&h5->unack.lock, flags); 559 spin_unlock_irqrestore(&h5->unack.lock, flags);
507 560
508 if (h5->txack_req) 561 if (h5->tx_ack_req)
509 return h5_prepare_ack(h5); 562 return h5_prepare_ack(h5);
510 563
511 return NULL; 564 return NULL;