Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1/* SPDX-License-Identifier: GPL-2.0-or-later */
  2/*
  3 *
  4 *  Generic Bluetooth HCI UART driver
  5 *
  6 *  Copyright (C) 2015-2018  Intel Corporation
  7 */
  8
  9#include <linux/unaligned.h>
 10
 11struct h4_recv_pkt {
 12	u8  type;	/* Packet type */
 13	u8  hlen;	/* Header length */
 14	u8  loff;	/* Data length offset in header */
 15	u8  lsize;	/* Data length field size */
 16	u16 maxlen;	/* Max overall packet length */
 17	int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
 18};
 19
 20#define H4_RECV_ACL \
 21	.type = HCI_ACLDATA_PKT, \
 22	.hlen = HCI_ACL_HDR_SIZE, \
 23	.loff = 2, \
 24	.lsize = 2, \
 25	.maxlen = HCI_MAX_FRAME_SIZE \
 26
 27#define H4_RECV_SCO \
 28	.type = HCI_SCODATA_PKT, \
 29	.hlen = HCI_SCO_HDR_SIZE, \
 30	.loff = 2, \
 31	.lsize = 1, \
 32	.maxlen = HCI_MAX_SCO_SIZE
 33
 34#define H4_RECV_EVENT \
 35	.type = HCI_EVENT_PKT, \
 36	.hlen = HCI_EVENT_HDR_SIZE, \
 37	.loff = 1, \
 38	.lsize = 1, \
 39	.maxlen = HCI_MAX_EVENT_SIZE
 40
 41#define H4_RECV_ISO \
 42	.type = HCI_ISODATA_PKT, \
 43	.hlen = HCI_ISO_HDR_SIZE, \
 44	.loff = 2, \
 45	.lsize = 2, \
 46	.maxlen = HCI_MAX_FRAME_SIZE
 47
 48static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,
 49					  struct sk_buff *skb,
 50					  const unsigned char *buffer,
 51					  int count,
 52					  const struct h4_recv_pkt *pkts,
 53					  int pkts_count)
 54{
 55	/* Check for error from previous call */
 56	if (IS_ERR(skb))
 57		skb = NULL;
 58
 59	while (count) {
 60		int i, len;
 61
 62		if (!skb) {
 63			for (i = 0; i < pkts_count; i++) {
 64				if (buffer[0] != (&pkts[i])->type)
 65					continue;
 66
 67				skb = bt_skb_alloc((&pkts[i])->maxlen,
 68						   GFP_ATOMIC);
 69				if (!skb)
 70					return ERR_PTR(-ENOMEM);
 71
 72				hci_skb_pkt_type(skb) = (&pkts[i])->type;
 73				hci_skb_expect(skb) = (&pkts[i])->hlen;
 74				break;
 75			}
 76
 77			/* Check for invalid packet type */
 78			if (!skb)
 79				return ERR_PTR(-EILSEQ);
 80
 81			count -= 1;
 82			buffer += 1;
 83		}
 84
 85		len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
 86		skb_put_data(skb, buffer, len);
 87
 88		count -= len;
 89		buffer += len;
 90
 91		/* Check for partial packet */
 92		if (skb->len < hci_skb_expect(skb))
 93			continue;
 94
 95		for (i = 0; i < pkts_count; i++) {
 96			if (hci_skb_pkt_type(skb) == (&pkts[i])->type)
 97				break;
 98		}
 99
100		if (i >= pkts_count) {
101			kfree_skb(skb);
102			return ERR_PTR(-EILSEQ);
103		}
104
105		if (skb->len == (&pkts[i])->hlen) {
106			u16 dlen;
107
108			switch ((&pkts[i])->lsize) {
109			case 0:
110				/* No variable data length */
111				dlen = 0;
112				break;
113			case 1:
114				/* Single octet variable length */
115				dlen = skb->data[(&pkts[i])->loff];
116				hci_skb_expect(skb) += dlen;
117
118				if (skb_tailroom(skb) < dlen) {
119					kfree_skb(skb);
120					return ERR_PTR(-EMSGSIZE);
121				}
122				break;
123			case 2:
124				/* Double octet variable length */
125				dlen = get_unaligned_le16(skb->data +
126							  (&pkts[i])->loff);
127				hci_skb_expect(skb) += dlen;
128
129				if (skb_tailroom(skb) < dlen) {
130					kfree_skb(skb);
131					return ERR_PTR(-EMSGSIZE);
132				}
133				break;
134			default:
135				/* Unsupported variable length */
136				kfree_skb(skb);
137				return ERR_PTR(-EILSEQ);
138			}
139
140			if (!dlen) {
141				/* No more data, complete frame */
142				(&pkts[i])->recv(hdev, skb);
143				skb = NULL;
144			}
145		} else {
146			/* Complete frame */
147			(&pkts[i])->recv(hdev, skb);
148			skb = NULL;
149		}
150	}
151
152	return skb;
153}