162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Generic Bluetooth HCI UART driver
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Copyright (C) 2015-2018  Intel Corporation
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <asm/unaligned.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistruct h4_recv_pkt {
1262306a36Sopenharmony_ci	u8  type;	/* Packet type */
1362306a36Sopenharmony_ci	u8  hlen;	/* Header length */
1462306a36Sopenharmony_ci	u8  loff;	/* Data length offset in header */
1562306a36Sopenharmony_ci	u8  lsize;	/* Data length field size */
1662306a36Sopenharmony_ci	u16 maxlen;	/* Max overall packet length */
1762306a36Sopenharmony_ci	int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
1862306a36Sopenharmony_ci};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define H4_RECV_ACL \
2162306a36Sopenharmony_ci	.type = HCI_ACLDATA_PKT, \
2262306a36Sopenharmony_ci	.hlen = HCI_ACL_HDR_SIZE, \
2362306a36Sopenharmony_ci	.loff = 2, \
2462306a36Sopenharmony_ci	.lsize = 2, \
2562306a36Sopenharmony_ci	.maxlen = HCI_MAX_FRAME_SIZE \
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define H4_RECV_SCO \
2862306a36Sopenharmony_ci	.type = HCI_SCODATA_PKT, \
2962306a36Sopenharmony_ci	.hlen = HCI_SCO_HDR_SIZE, \
3062306a36Sopenharmony_ci	.loff = 2, \
3162306a36Sopenharmony_ci	.lsize = 1, \
3262306a36Sopenharmony_ci	.maxlen = HCI_MAX_SCO_SIZE
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define H4_RECV_EVENT \
3562306a36Sopenharmony_ci	.type = HCI_EVENT_PKT, \
3662306a36Sopenharmony_ci	.hlen = HCI_EVENT_HDR_SIZE, \
3762306a36Sopenharmony_ci	.loff = 1, \
3862306a36Sopenharmony_ci	.lsize = 1, \
3962306a36Sopenharmony_ci	.maxlen = HCI_MAX_EVENT_SIZE
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,
4262306a36Sopenharmony_ci					  struct sk_buff *skb,
4362306a36Sopenharmony_ci					  const unsigned char *buffer,
4462306a36Sopenharmony_ci					  int count,
4562306a36Sopenharmony_ci					  const struct h4_recv_pkt *pkts,
4662306a36Sopenharmony_ci					  int pkts_count)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	/* Check for error from previous call */
4962306a36Sopenharmony_ci	if (IS_ERR(skb))
5062306a36Sopenharmony_ci		skb = NULL;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	while (count) {
5362306a36Sopenharmony_ci		int i, len;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci		if (!skb) {
5662306a36Sopenharmony_ci			for (i = 0; i < pkts_count; i++) {
5762306a36Sopenharmony_ci				if (buffer[0] != (&pkts[i])->type)
5862306a36Sopenharmony_ci					continue;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci				skb = bt_skb_alloc((&pkts[i])->maxlen,
6162306a36Sopenharmony_ci						   GFP_ATOMIC);
6262306a36Sopenharmony_ci				if (!skb)
6362306a36Sopenharmony_ci					return ERR_PTR(-ENOMEM);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci				hci_skb_pkt_type(skb) = (&pkts[i])->type;
6662306a36Sopenharmony_ci				hci_skb_expect(skb) = (&pkts[i])->hlen;
6762306a36Sopenharmony_ci				break;
6862306a36Sopenharmony_ci			}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci			/* Check for invalid packet type */
7162306a36Sopenharmony_ci			if (!skb)
7262306a36Sopenharmony_ci				return ERR_PTR(-EILSEQ);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci			count -= 1;
7562306a36Sopenharmony_ci			buffer += 1;
7662306a36Sopenharmony_ci		}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
7962306a36Sopenharmony_ci		skb_put_data(skb, buffer, len);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci		count -= len;
8262306a36Sopenharmony_ci		buffer += len;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		/* Check for partial packet */
8562306a36Sopenharmony_ci		if (skb->len < hci_skb_expect(skb))
8662306a36Sopenharmony_ci			continue;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci		for (i = 0; i < pkts_count; i++) {
8962306a36Sopenharmony_ci			if (hci_skb_pkt_type(skb) == (&pkts[i])->type)
9062306a36Sopenharmony_ci				break;
9162306a36Sopenharmony_ci		}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		if (i >= pkts_count) {
9462306a36Sopenharmony_ci			kfree_skb(skb);
9562306a36Sopenharmony_ci			return ERR_PTR(-EILSEQ);
9662306a36Sopenharmony_ci		}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		if (skb->len == (&pkts[i])->hlen) {
9962306a36Sopenharmony_ci			u16 dlen;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci			switch ((&pkts[i])->lsize) {
10262306a36Sopenharmony_ci			case 0:
10362306a36Sopenharmony_ci				/* No variable data length */
10462306a36Sopenharmony_ci				dlen = 0;
10562306a36Sopenharmony_ci				break;
10662306a36Sopenharmony_ci			case 1:
10762306a36Sopenharmony_ci				/* Single octet variable length */
10862306a36Sopenharmony_ci				dlen = skb->data[(&pkts[i])->loff];
10962306a36Sopenharmony_ci				hci_skb_expect(skb) += dlen;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci				if (skb_tailroom(skb) < dlen) {
11262306a36Sopenharmony_ci					kfree_skb(skb);
11362306a36Sopenharmony_ci					return ERR_PTR(-EMSGSIZE);
11462306a36Sopenharmony_ci				}
11562306a36Sopenharmony_ci				break;
11662306a36Sopenharmony_ci			case 2:
11762306a36Sopenharmony_ci				/* Double octet variable length */
11862306a36Sopenharmony_ci				dlen = get_unaligned_le16(skb->data +
11962306a36Sopenharmony_ci							  (&pkts[i])->loff);
12062306a36Sopenharmony_ci				hci_skb_expect(skb) += dlen;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci				if (skb_tailroom(skb) < dlen) {
12362306a36Sopenharmony_ci					kfree_skb(skb);
12462306a36Sopenharmony_ci					return ERR_PTR(-EMSGSIZE);
12562306a36Sopenharmony_ci				}
12662306a36Sopenharmony_ci				break;
12762306a36Sopenharmony_ci			default:
12862306a36Sopenharmony_ci				/* Unsupported variable length */
12962306a36Sopenharmony_ci				kfree_skb(skb);
13062306a36Sopenharmony_ci				return ERR_PTR(-EILSEQ);
13162306a36Sopenharmony_ci			}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci			if (!dlen) {
13462306a36Sopenharmony_ci				/* No more data, complete frame */
13562306a36Sopenharmony_ci				(&pkts[i])->recv(hdev, skb);
13662306a36Sopenharmony_ci				skb = NULL;
13762306a36Sopenharmony_ci			}
13862306a36Sopenharmony_ci		} else {
13962306a36Sopenharmony_ci			/* Complete frame */
14062306a36Sopenharmony_ci			(&pkts[i])->recv(hdev, skb);
14162306a36Sopenharmony_ci			skb = NULL;
14262306a36Sopenharmony_ci		}
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return skb;
14662306a36Sopenharmony_ci}
147