107eb96a5SMarcel Holtmann /* 207eb96a5SMarcel Holtmann * 307eb96a5SMarcel Holtmann * Generic Bluetooth HCI UART driver 407eb96a5SMarcel Holtmann * 507eb96a5SMarcel Holtmann * Copyright (C) 2015-2018 Intel Corporation 607eb96a5SMarcel Holtmann * 707eb96a5SMarcel Holtmann * 807eb96a5SMarcel Holtmann * This program is free software; you can redistribute it and/or modify 907eb96a5SMarcel Holtmann * it under the terms of the GNU General Public License as published by 1007eb96a5SMarcel Holtmann * the Free Software Foundation; either version 2 of the License, or 1107eb96a5SMarcel Holtmann * (at your option) any later version. 1207eb96a5SMarcel Holtmann * 1307eb96a5SMarcel Holtmann * This program is distributed in the hope that it will be useful, 1407eb96a5SMarcel Holtmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 1507eb96a5SMarcel Holtmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1607eb96a5SMarcel Holtmann * GNU General Public License for more details. 1707eb96a5SMarcel Holtmann * 1807eb96a5SMarcel Holtmann * You should have received a copy of the GNU General Public License 1907eb96a5SMarcel Holtmann * along with this program; if not, write to the Free Software 2007eb96a5SMarcel Holtmann * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2107eb96a5SMarcel Holtmann * 2207eb96a5SMarcel Holtmann */ 2307eb96a5SMarcel Holtmann 2407eb96a5SMarcel Holtmann #include <asm/unaligned.h> 2507eb96a5SMarcel Holtmann 2607eb96a5SMarcel Holtmann struct h4_recv_pkt { 2707eb96a5SMarcel Holtmann u8 type; /* Packet type */ 2807eb96a5SMarcel Holtmann u8 hlen; /* Header length */ 2907eb96a5SMarcel Holtmann u8 loff; /* Data length offset in header */ 3007eb96a5SMarcel Holtmann u8 lsize; /* Data length field size */ 3107eb96a5SMarcel Holtmann u16 maxlen; /* Max overall packet length */ 3207eb96a5SMarcel Holtmann int (*recv)(struct hci_dev *hdev, struct sk_buff *skb); 3307eb96a5SMarcel Holtmann }; 3407eb96a5SMarcel Holtmann 3507eb96a5SMarcel Holtmann #define H4_RECV_ACL \ 3607eb96a5SMarcel Holtmann .type = HCI_ACLDATA_PKT, \ 3707eb96a5SMarcel Holtmann .hlen = HCI_ACL_HDR_SIZE, \ 3807eb96a5SMarcel Holtmann .loff = 2, \ 3907eb96a5SMarcel Holtmann .lsize = 2, \ 4007eb96a5SMarcel Holtmann .maxlen = HCI_MAX_FRAME_SIZE \ 4107eb96a5SMarcel Holtmann 4207eb96a5SMarcel Holtmann #define H4_RECV_SCO \ 4307eb96a5SMarcel Holtmann .type = HCI_SCODATA_PKT, \ 4407eb96a5SMarcel Holtmann .hlen = HCI_SCO_HDR_SIZE, \ 4507eb96a5SMarcel Holtmann .loff = 2, \ 4607eb96a5SMarcel Holtmann .lsize = 1, \ 4707eb96a5SMarcel Holtmann .maxlen = HCI_MAX_SCO_SIZE 4807eb96a5SMarcel Holtmann 4907eb96a5SMarcel Holtmann #define H4_RECV_EVENT \ 5007eb96a5SMarcel Holtmann .type = HCI_EVENT_PKT, \ 5107eb96a5SMarcel Holtmann .hlen = HCI_EVENT_HDR_SIZE, \ 5207eb96a5SMarcel Holtmann .loff = 1, \ 5307eb96a5SMarcel Holtmann .lsize = 1, \ 5407eb96a5SMarcel Holtmann .maxlen = HCI_MAX_EVENT_SIZE 5507eb96a5SMarcel Holtmann 5607eb96a5SMarcel Holtmann static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev, 5707eb96a5SMarcel Holtmann struct sk_buff *skb, 5807eb96a5SMarcel Holtmann const unsigned char *buffer, 5907eb96a5SMarcel Holtmann int count, 6007eb96a5SMarcel Holtmann const struct h4_recv_pkt *pkts, 6107eb96a5SMarcel Holtmann int pkts_count) 6207eb96a5SMarcel Holtmann { 63*1dc2d785SMyungho Jung /* Check for error from previous call */ 64*1dc2d785SMyungho Jung if (IS_ERR(skb)) 65*1dc2d785SMyungho Jung skb = NULL; 66*1dc2d785SMyungho Jung 6707eb96a5SMarcel Holtmann while (count) { 6807eb96a5SMarcel Holtmann int i, len; 6907eb96a5SMarcel Holtmann 7007eb96a5SMarcel Holtmann if (!count) 7107eb96a5SMarcel Holtmann break; 7207eb96a5SMarcel Holtmann 7307eb96a5SMarcel Holtmann if (!skb) { 7407eb96a5SMarcel Holtmann for (i = 0; i < pkts_count; i++) { 7507eb96a5SMarcel Holtmann if (buffer[0] != (&pkts[i])->type) 7607eb96a5SMarcel Holtmann continue; 7707eb96a5SMarcel Holtmann 7807eb96a5SMarcel Holtmann skb = bt_skb_alloc((&pkts[i])->maxlen, 7907eb96a5SMarcel Holtmann GFP_ATOMIC); 8007eb96a5SMarcel Holtmann if (!skb) 8107eb96a5SMarcel Holtmann return ERR_PTR(-ENOMEM); 8207eb96a5SMarcel Holtmann 8307eb96a5SMarcel Holtmann hci_skb_pkt_type(skb) = (&pkts[i])->type; 8407eb96a5SMarcel Holtmann hci_skb_expect(skb) = (&pkts[i])->hlen; 8507eb96a5SMarcel Holtmann break; 8607eb96a5SMarcel Holtmann } 8707eb96a5SMarcel Holtmann 8807eb96a5SMarcel Holtmann /* Check for invalid packet type */ 8907eb96a5SMarcel Holtmann if (!skb) 9007eb96a5SMarcel Holtmann return ERR_PTR(-EILSEQ); 9107eb96a5SMarcel Holtmann 9207eb96a5SMarcel Holtmann count -= 1; 9307eb96a5SMarcel Holtmann buffer += 1; 9407eb96a5SMarcel Holtmann } 9507eb96a5SMarcel Holtmann 9607eb96a5SMarcel Holtmann len = min_t(uint, hci_skb_expect(skb) - skb->len, count); 9707eb96a5SMarcel Holtmann skb_put_data(skb, buffer, len); 9807eb96a5SMarcel Holtmann 9907eb96a5SMarcel Holtmann count -= len; 10007eb96a5SMarcel Holtmann buffer += len; 10107eb96a5SMarcel Holtmann 10207eb96a5SMarcel Holtmann /* Check for partial packet */ 10307eb96a5SMarcel Holtmann if (skb->len < hci_skb_expect(skb)) 10407eb96a5SMarcel Holtmann continue; 10507eb96a5SMarcel Holtmann 10607eb96a5SMarcel Holtmann for (i = 0; i < pkts_count; i++) { 10707eb96a5SMarcel Holtmann if (hci_skb_pkt_type(skb) == (&pkts[i])->type) 10807eb96a5SMarcel Holtmann break; 10907eb96a5SMarcel Holtmann } 11007eb96a5SMarcel Holtmann 11107eb96a5SMarcel Holtmann if (i >= pkts_count) { 11207eb96a5SMarcel Holtmann kfree_skb(skb); 11307eb96a5SMarcel Holtmann return ERR_PTR(-EILSEQ); 11407eb96a5SMarcel Holtmann } 11507eb96a5SMarcel Holtmann 11607eb96a5SMarcel Holtmann if (skb->len == (&pkts[i])->hlen) { 11707eb96a5SMarcel Holtmann u16 dlen; 11807eb96a5SMarcel Holtmann 11907eb96a5SMarcel Holtmann switch ((&pkts[i])->lsize) { 12007eb96a5SMarcel Holtmann case 0: 12107eb96a5SMarcel Holtmann /* No variable data length */ 12207eb96a5SMarcel Holtmann dlen = 0; 12307eb96a5SMarcel Holtmann break; 12407eb96a5SMarcel Holtmann case 1: 12507eb96a5SMarcel Holtmann /* Single octet variable length */ 12607eb96a5SMarcel Holtmann dlen = skb->data[(&pkts[i])->loff]; 12707eb96a5SMarcel Holtmann hci_skb_expect(skb) += dlen; 12807eb96a5SMarcel Holtmann 12907eb96a5SMarcel Holtmann if (skb_tailroom(skb) < dlen) { 13007eb96a5SMarcel Holtmann kfree_skb(skb); 13107eb96a5SMarcel Holtmann return ERR_PTR(-EMSGSIZE); 13207eb96a5SMarcel Holtmann } 13307eb96a5SMarcel Holtmann break; 13407eb96a5SMarcel Holtmann case 2: 13507eb96a5SMarcel Holtmann /* Double octet variable length */ 13607eb96a5SMarcel Holtmann dlen = get_unaligned_le16(skb->data + 13707eb96a5SMarcel Holtmann (&pkts[i])->loff); 13807eb96a5SMarcel Holtmann hci_skb_expect(skb) += dlen; 13907eb96a5SMarcel Holtmann 14007eb96a5SMarcel Holtmann if (skb_tailroom(skb) < dlen) { 14107eb96a5SMarcel Holtmann kfree_skb(skb); 14207eb96a5SMarcel Holtmann return ERR_PTR(-EMSGSIZE); 14307eb96a5SMarcel Holtmann } 14407eb96a5SMarcel Holtmann break; 14507eb96a5SMarcel Holtmann default: 14607eb96a5SMarcel Holtmann /* Unsupported variable length */ 14707eb96a5SMarcel Holtmann kfree_skb(skb); 14807eb96a5SMarcel Holtmann return ERR_PTR(-EILSEQ); 14907eb96a5SMarcel Holtmann } 15007eb96a5SMarcel Holtmann 15107eb96a5SMarcel Holtmann if (!dlen) { 15207eb96a5SMarcel Holtmann /* No more data, complete frame */ 15307eb96a5SMarcel Holtmann (&pkts[i])->recv(hdev, skb); 15407eb96a5SMarcel Holtmann skb = NULL; 15507eb96a5SMarcel Holtmann } 15607eb96a5SMarcel Holtmann } else { 15707eb96a5SMarcel Holtmann /* Complete frame */ 15807eb96a5SMarcel Holtmann (&pkts[i])->recv(hdev, skb); 15907eb96a5SMarcel Holtmann skb = NULL; 16007eb96a5SMarcel Holtmann } 16107eb96a5SMarcel Holtmann } 16207eb96a5SMarcel Holtmann 16307eb96a5SMarcel Holtmann return skb; 16407eb96a5SMarcel Holtmann } 165