brintos

brintos / linux-shallow public Read only

0
0
Text · 3.1 KiB · 28cf2d8 Raw
154 lines · c
1/* SPDX-License-Identifier: GPL-2.0-or-later */2/*3 *4 *  Generic Bluetooth HCI UART driver5 *6 *  Copyright (C) 2015-2018  Intel Corporation7 */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_SIZE33 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_SIZE40 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_SIZE47 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}154