1*1a59d1b8SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */ 207eb96a5SMarcel Holtmann /* 307eb96a5SMarcel Holtmann * 407eb96a5SMarcel Holtmann * Generic Bluetooth HCI UART driver 507eb96a5SMarcel Holtmann * 607eb96a5SMarcel Holtmann * Copyright (C) 2015-2018 Intel Corporation 707eb96a5SMarcel Holtmann */ 807eb96a5SMarcel Holtmann 907eb96a5SMarcel Holtmann #include <asm/unaligned.h> 1007eb96a5SMarcel Holtmann 1107eb96a5SMarcel Holtmann struct h4_recv_pkt { 1207eb96a5SMarcel Holtmann u8 type; /* Packet type */ 1307eb96a5SMarcel Holtmann u8 hlen; /* Header length */ 1407eb96a5SMarcel Holtmann u8 loff; /* Data length offset in header */ 1507eb96a5SMarcel Holtmann u8 lsize; /* Data length field size */ 1607eb96a5SMarcel Holtmann u16 maxlen; /* Max overall packet length */ 1707eb96a5SMarcel Holtmann int (*recv)(struct hci_dev *hdev, struct sk_buff *skb); 1807eb96a5SMarcel Holtmann }; 1907eb96a5SMarcel Holtmann 2007eb96a5SMarcel Holtmann #define H4_RECV_ACL \ 2107eb96a5SMarcel Holtmann .type = HCI_ACLDATA_PKT, \ 2207eb96a5SMarcel Holtmann .hlen = HCI_ACL_HDR_SIZE, \ 2307eb96a5SMarcel Holtmann .loff = 2, \ 2407eb96a5SMarcel Holtmann .lsize = 2, \ 2507eb96a5SMarcel Holtmann .maxlen = HCI_MAX_FRAME_SIZE \ 2607eb96a5SMarcel Holtmann 2707eb96a5SMarcel Holtmann #define H4_RECV_SCO \ 2807eb96a5SMarcel Holtmann .type = HCI_SCODATA_PKT, \ 2907eb96a5SMarcel Holtmann .hlen = HCI_SCO_HDR_SIZE, \ 3007eb96a5SMarcel Holtmann .loff = 2, \ 3107eb96a5SMarcel Holtmann .lsize = 1, \ 3207eb96a5SMarcel Holtmann .maxlen = HCI_MAX_SCO_SIZE 3307eb96a5SMarcel Holtmann 3407eb96a5SMarcel Holtmann #define H4_RECV_EVENT \ 3507eb96a5SMarcel Holtmann .type = HCI_EVENT_PKT, \ 3607eb96a5SMarcel Holtmann .hlen = HCI_EVENT_HDR_SIZE, \ 3707eb96a5SMarcel Holtmann .loff = 1, \ 3807eb96a5SMarcel Holtmann .lsize = 1, \ 3907eb96a5SMarcel Holtmann .maxlen = HCI_MAX_EVENT_SIZE 4007eb96a5SMarcel Holtmann 4107eb96a5SMarcel Holtmann static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev, 4207eb96a5SMarcel Holtmann struct sk_buff *skb, 4307eb96a5SMarcel Holtmann const unsigned char *buffer, 4407eb96a5SMarcel Holtmann int count, 4507eb96a5SMarcel Holtmann const struct h4_recv_pkt *pkts, 4607eb96a5SMarcel Holtmann int pkts_count) 4707eb96a5SMarcel Holtmann { 481dc2d785SMyungho Jung /* Check for error from previous call */ 491dc2d785SMyungho Jung if (IS_ERR(skb)) 501dc2d785SMyungho Jung skb = NULL; 511dc2d785SMyungho Jung 5207eb96a5SMarcel Holtmann while (count) { 5307eb96a5SMarcel Holtmann int i, len; 5407eb96a5SMarcel Holtmann 5507eb96a5SMarcel Holtmann if (!skb) { 5607eb96a5SMarcel Holtmann for (i = 0; i < pkts_count; i++) { 5707eb96a5SMarcel Holtmann if (buffer[0] != (&pkts[i])->type) 5807eb96a5SMarcel Holtmann continue; 5907eb96a5SMarcel Holtmann 6007eb96a5SMarcel Holtmann skb = bt_skb_alloc((&pkts[i])->maxlen, 6107eb96a5SMarcel Holtmann GFP_ATOMIC); 6207eb96a5SMarcel Holtmann if (!skb) 6307eb96a5SMarcel Holtmann return ERR_PTR(-ENOMEM); 6407eb96a5SMarcel Holtmann 6507eb96a5SMarcel Holtmann hci_skb_pkt_type(skb) = (&pkts[i])->type; 6607eb96a5SMarcel Holtmann hci_skb_expect(skb) = (&pkts[i])->hlen; 6707eb96a5SMarcel Holtmann break; 6807eb96a5SMarcel Holtmann } 6907eb96a5SMarcel Holtmann 7007eb96a5SMarcel Holtmann /* Check for invalid packet type */ 7107eb96a5SMarcel Holtmann if (!skb) 7207eb96a5SMarcel Holtmann return ERR_PTR(-EILSEQ); 7307eb96a5SMarcel Holtmann 7407eb96a5SMarcel Holtmann count -= 1; 7507eb96a5SMarcel Holtmann buffer += 1; 7607eb96a5SMarcel Holtmann } 7707eb96a5SMarcel Holtmann 7807eb96a5SMarcel Holtmann len = min_t(uint, hci_skb_expect(skb) - skb->len, count); 7907eb96a5SMarcel Holtmann skb_put_data(skb, buffer, len); 8007eb96a5SMarcel Holtmann 8107eb96a5SMarcel Holtmann count -= len; 8207eb96a5SMarcel Holtmann buffer += len; 8307eb96a5SMarcel Holtmann 8407eb96a5SMarcel Holtmann /* Check for partial packet */ 8507eb96a5SMarcel Holtmann if (skb->len < hci_skb_expect(skb)) 8607eb96a5SMarcel Holtmann continue; 8707eb96a5SMarcel Holtmann 8807eb96a5SMarcel Holtmann for (i = 0; i < pkts_count; i++) { 8907eb96a5SMarcel Holtmann if (hci_skb_pkt_type(skb) == (&pkts[i])->type) 9007eb96a5SMarcel Holtmann break; 9107eb96a5SMarcel Holtmann } 9207eb96a5SMarcel Holtmann 9307eb96a5SMarcel Holtmann if (i >= pkts_count) { 9407eb96a5SMarcel Holtmann kfree_skb(skb); 9507eb96a5SMarcel Holtmann return ERR_PTR(-EILSEQ); 9607eb96a5SMarcel Holtmann } 9707eb96a5SMarcel Holtmann 9807eb96a5SMarcel Holtmann if (skb->len == (&pkts[i])->hlen) { 9907eb96a5SMarcel Holtmann u16 dlen; 10007eb96a5SMarcel Holtmann 10107eb96a5SMarcel Holtmann switch ((&pkts[i])->lsize) { 10207eb96a5SMarcel Holtmann case 0: 10307eb96a5SMarcel Holtmann /* No variable data length */ 10407eb96a5SMarcel Holtmann dlen = 0; 10507eb96a5SMarcel Holtmann break; 10607eb96a5SMarcel Holtmann case 1: 10707eb96a5SMarcel Holtmann /* Single octet variable length */ 10807eb96a5SMarcel Holtmann dlen = skb->data[(&pkts[i])->loff]; 10907eb96a5SMarcel Holtmann hci_skb_expect(skb) += dlen; 11007eb96a5SMarcel Holtmann 11107eb96a5SMarcel Holtmann if (skb_tailroom(skb) < dlen) { 11207eb96a5SMarcel Holtmann kfree_skb(skb); 11307eb96a5SMarcel Holtmann return ERR_PTR(-EMSGSIZE); 11407eb96a5SMarcel Holtmann } 11507eb96a5SMarcel Holtmann break; 11607eb96a5SMarcel Holtmann case 2: 11707eb96a5SMarcel Holtmann /* Double octet variable length */ 11807eb96a5SMarcel Holtmann dlen = get_unaligned_le16(skb->data + 11907eb96a5SMarcel Holtmann (&pkts[i])->loff); 12007eb96a5SMarcel Holtmann hci_skb_expect(skb) += dlen; 12107eb96a5SMarcel Holtmann 12207eb96a5SMarcel Holtmann if (skb_tailroom(skb) < dlen) { 12307eb96a5SMarcel Holtmann kfree_skb(skb); 12407eb96a5SMarcel Holtmann return ERR_PTR(-EMSGSIZE); 12507eb96a5SMarcel Holtmann } 12607eb96a5SMarcel Holtmann break; 12707eb96a5SMarcel Holtmann default: 12807eb96a5SMarcel Holtmann /* Unsupported variable length */ 12907eb96a5SMarcel Holtmann kfree_skb(skb); 13007eb96a5SMarcel Holtmann return ERR_PTR(-EILSEQ); 13107eb96a5SMarcel Holtmann } 13207eb96a5SMarcel Holtmann 13307eb96a5SMarcel Holtmann if (!dlen) { 13407eb96a5SMarcel Holtmann /* No more data, complete frame */ 13507eb96a5SMarcel Holtmann (&pkts[i])->recv(hdev, skb); 13607eb96a5SMarcel Holtmann skb = NULL; 13707eb96a5SMarcel Holtmann } 13807eb96a5SMarcel Holtmann } else { 13907eb96a5SMarcel Holtmann /* Complete frame */ 14007eb96a5SMarcel Holtmann (&pkts[i])->recv(hdev, skb); 14107eb96a5SMarcel Holtmann skb = NULL; 14207eb96a5SMarcel Holtmann } 14307eb96a5SMarcel Holtmann } 14407eb96a5SMarcel Holtmann 14507eb96a5SMarcel Holtmann return skb; 14607eb96a5SMarcel Holtmann } 147