in hci_bcsp.c [474:572]
static void bcsp_complete_rx_pkt(struct hci_uart *hu)
{
struct bcsp_struct *bcsp = hu->priv;
int pass_up = 0;
if (bcsp->rx_skb->data[0] & 0x80) { /* reliable pkt */
BT_DBG("Received seqno %u from card", bcsp->rxseq_txack);
/* check the rx sequence number is as expected */
if ((bcsp->rx_skb->data[0] & 0x07) == bcsp->rxseq_txack) {
bcsp->rxseq_txack++;
bcsp->rxseq_txack %= 0x8;
} else {
/* handle re-transmitted packet or
* when packet was missed
*/
BT_ERR("Out-of-order packet arrived, got %u expected %u",
bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
/* do not process out-of-order packet payload */
pass_up = 2;
}
/* send current txack value to all received reliable packets */
bcsp->txack_req = 1;
/* If needed, transmit an ack pkt */
hci_uart_tx_wakeup(hu);
}
bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07;
BT_DBG("Request for pkt %u from card", bcsp->rxack);
/* handle received ACK indications,
* including those from out-of-order packets
*/
bcsp_pkt_cull(bcsp);
if (pass_up != 2) {
if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
(bcsp->rx_skb->data[0] & 0x80)) {
hci_skb_pkt_type(bcsp->rx_skb) = HCI_ACLDATA_PKT;
pass_up = 1;
} else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
(bcsp->rx_skb->data[0] & 0x80)) {
hci_skb_pkt_type(bcsp->rx_skb) = HCI_EVENT_PKT;
pass_up = 1;
} else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
hci_skb_pkt_type(bcsp->rx_skb) = HCI_SCODATA_PKT;
pass_up = 1;
} else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
!(bcsp->rx_skb->data[0] & 0x80)) {
bcsp_handle_le_pkt(hu);
pass_up = 0;
} else {
pass_up = 0;
}
}
if (pass_up == 0) {
struct hci_event_hdr hdr;
u8 desc = (bcsp->rx_skb->data[1] & 0x0f);
if (desc != 0 && desc != 1) {
if (hciextn) {
desc |= 0xc0;
skb_pull(bcsp->rx_skb, 4);
memcpy(skb_push(bcsp->rx_skb, 1), &desc, 1);
hdr.evt = 0xff;
hdr.plen = bcsp->rx_skb->len;
memcpy(skb_push(bcsp->rx_skb, HCI_EVENT_HDR_SIZE), &hdr, HCI_EVENT_HDR_SIZE);
hci_skb_pkt_type(bcsp->rx_skb) = HCI_EVENT_PKT;
hci_recv_frame(hu->hdev, bcsp->rx_skb);
} else {
BT_ERR("Packet for unknown channel (%u %s)",
bcsp->rx_skb->data[1] & 0x0f,
bcsp->rx_skb->data[0] & 0x80 ?
"reliable" : "unreliable");
kfree_skb(bcsp->rx_skb);
}
} else
kfree_skb(bcsp->rx_skb);
} else if (pass_up == 1) {
/* Pull out BCSP hdr */
skb_pull(bcsp->rx_skb, 4);
hci_recv_frame(hu->hdev, bcsp->rx_skb);
} else {
/* ignore packet payload of already ACKed re-transmitted
* packets or when a packet was missed in the BCSP window
*/
kfree_skb(bcsp->rx_skb);
}
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
bcsp->rx_skb = NULL;
}