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
h4_recv_buf(struct hci_dev * hdev,struct sk_buff * skb,const unsigned char * buffer,int count,const struct h4_recv_pkt * pkts,int pkts_count)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