xref: /openbmc/linux/drivers/bluetooth/h4_recv.h (revision 07eb96a5a7b083c988a2c7b0663e958e392f18c7)
1*07eb96a5SMarcel Holtmann /*
2*07eb96a5SMarcel Holtmann  *
3*07eb96a5SMarcel Holtmann  *  Generic Bluetooth HCI UART driver
4*07eb96a5SMarcel Holtmann  *
5*07eb96a5SMarcel Holtmann  *  Copyright (C) 2015-2018  Intel Corporation
6*07eb96a5SMarcel Holtmann  *
7*07eb96a5SMarcel Holtmann  *
8*07eb96a5SMarcel Holtmann  *  This program is free software; you can redistribute it and/or modify
9*07eb96a5SMarcel Holtmann  *  it under the terms of the GNU General Public License as published by
10*07eb96a5SMarcel Holtmann  *  the Free Software Foundation; either version 2 of the License, or
11*07eb96a5SMarcel Holtmann  *  (at your option) any later version.
12*07eb96a5SMarcel Holtmann  *
13*07eb96a5SMarcel Holtmann  *  This program is distributed in the hope that it will be useful,
14*07eb96a5SMarcel Holtmann  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15*07eb96a5SMarcel Holtmann  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*07eb96a5SMarcel Holtmann  *  GNU General Public License for more details.
17*07eb96a5SMarcel Holtmann  *
18*07eb96a5SMarcel Holtmann  *  You should have received a copy of the GNU General Public License
19*07eb96a5SMarcel Holtmann  *  along with this program; if not, write to the Free Software
20*07eb96a5SMarcel Holtmann  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21*07eb96a5SMarcel Holtmann  *
22*07eb96a5SMarcel Holtmann  */
23*07eb96a5SMarcel Holtmann 
24*07eb96a5SMarcel Holtmann #include <asm/unaligned.h>
25*07eb96a5SMarcel Holtmann 
26*07eb96a5SMarcel Holtmann struct h4_recv_pkt {
27*07eb96a5SMarcel Holtmann 	u8  type;	/* Packet type */
28*07eb96a5SMarcel Holtmann 	u8  hlen;	/* Header length */
29*07eb96a5SMarcel Holtmann 	u8  loff;	/* Data length offset in header */
30*07eb96a5SMarcel Holtmann 	u8  lsize;	/* Data length field size */
31*07eb96a5SMarcel Holtmann 	u16 maxlen;	/* Max overall packet length */
32*07eb96a5SMarcel Holtmann 	int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
33*07eb96a5SMarcel Holtmann };
34*07eb96a5SMarcel Holtmann 
35*07eb96a5SMarcel Holtmann #define H4_RECV_ACL \
36*07eb96a5SMarcel Holtmann 	.type = HCI_ACLDATA_PKT, \
37*07eb96a5SMarcel Holtmann 	.hlen = HCI_ACL_HDR_SIZE, \
38*07eb96a5SMarcel Holtmann 	.loff = 2, \
39*07eb96a5SMarcel Holtmann 	.lsize = 2, \
40*07eb96a5SMarcel Holtmann 	.maxlen = HCI_MAX_FRAME_SIZE \
41*07eb96a5SMarcel Holtmann 
42*07eb96a5SMarcel Holtmann #define H4_RECV_SCO \
43*07eb96a5SMarcel Holtmann 	.type = HCI_SCODATA_PKT, \
44*07eb96a5SMarcel Holtmann 	.hlen = HCI_SCO_HDR_SIZE, \
45*07eb96a5SMarcel Holtmann 	.loff = 2, \
46*07eb96a5SMarcel Holtmann 	.lsize = 1, \
47*07eb96a5SMarcel Holtmann 	.maxlen = HCI_MAX_SCO_SIZE
48*07eb96a5SMarcel Holtmann 
49*07eb96a5SMarcel Holtmann #define H4_RECV_EVENT \
50*07eb96a5SMarcel Holtmann 	.type = HCI_EVENT_PKT, \
51*07eb96a5SMarcel Holtmann 	.hlen = HCI_EVENT_HDR_SIZE, \
52*07eb96a5SMarcel Holtmann 	.loff = 1, \
53*07eb96a5SMarcel Holtmann 	.lsize = 1, \
54*07eb96a5SMarcel Holtmann 	.maxlen = HCI_MAX_EVENT_SIZE
55*07eb96a5SMarcel Holtmann 
56*07eb96a5SMarcel Holtmann static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,
57*07eb96a5SMarcel Holtmann 					  struct sk_buff *skb,
58*07eb96a5SMarcel Holtmann 					  const unsigned char *buffer,
59*07eb96a5SMarcel Holtmann 					  int count,
60*07eb96a5SMarcel Holtmann 					  const struct h4_recv_pkt *pkts,
61*07eb96a5SMarcel Holtmann 					  int pkts_count)
62*07eb96a5SMarcel Holtmann {
63*07eb96a5SMarcel Holtmann 	while (count) {
64*07eb96a5SMarcel Holtmann 		int i, len;
65*07eb96a5SMarcel Holtmann 
66*07eb96a5SMarcel Holtmann 		if (!count)
67*07eb96a5SMarcel Holtmann 			break;
68*07eb96a5SMarcel Holtmann 
69*07eb96a5SMarcel Holtmann 		if (!skb) {
70*07eb96a5SMarcel Holtmann 			for (i = 0; i < pkts_count; i++) {
71*07eb96a5SMarcel Holtmann 				if (buffer[0] != (&pkts[i])->type)
72*07eb96a5SMarcel Holtmann 					continue;
73*07eb96a5SMarcel Holtmann 
74*07eb96a5SMarcel Holtmann 				skb = bt_skb_alloc((&pkts[i])->maxlen,
75*07eb96a5SMarcel Holtmann 						   GFP_ATOMIC);
76*07eb96a5SMarcel Holtmann 				if (!skb)
77*07eb96a5SMarcel Holtmann 					return ERR_PTR(-ENOMEM);
78*07eb96a5SMarcel Holtmann 
79*07eb96a5SMarcel Holtmann 				hci_skb_pkt_type(skb) = (&pkts[i])->type;
80*07eb96a5SMarcel Holtmann 				hci_skb_expect(skb) = (&pkts[i])->hlen;
81*07eb96a5SMarcel Holtmann 				break;
82*07eb96a5SMarcel Holtmann 			}
83*07eb96a5SMarcel Holtmann 
84*07eb96a5SMarcel Holtmann 			/* Check for invalid packet type */
85*07eb96a5SMarcel Holtmann 			if (!skb)
86*07eb96a5SMarcel Holtmann 				return ERR_PTR(-EILSEQ);
87*07eb96a5SMarcel Holtmann 
88*07eb96a5SMarcel Holtmann 			count -= 1;
89*07eb96a5SMarcel Holtmann 			buffer += 1;
90*07eb96a5SMarcel Holtmann 		}
91*07eb96a5SMarcel Holtmann 
92*07eb96a5SMarcel Holtmann 		len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
93*07eb96a5SMarcel Holtmann 		skb_put_data(skb, buffer, len);
94*07eb96a5SMarcel Holtmann 
95*07eb96a5SMarcel Holtmann 		count -= len;
96*07eb96a5SMarcel Holtmann 		buffer += len;
97*07eb96a5SMarcel Holtmann 
98*07eb96a5SMarcel Holtmann 		/* Check for partial packet */
99*07eb96a5SMarcel Holtmann 		if (skb->len < hci_skb_expect(skb))
100*07eb96a5SMarcel Holtmann 			continue;
101*07eb96a5SMarcel Holtmann 
102*07eb96a5SMarcel Holtmann 		for (i = 0; i < pkts_count; i++) {
103*07eb96a5SMarcel Holtmann 			if (hci_skb_pkt_type(skb) == (&pkts[i])->type)
104*07eb96a5SMarcel Holtmann 				break;
105*07eb96a5SMarcel Holtmann 		}
106*07eb96a5SMarcel Holtmann 
107*07eb96a5SMarcel Holtmann 		if (i >= pkts_count) {
108*07eb96a5SMarcel Holtmann 			kfree_skb(skb);
109*07eb96a5SMarcel Holtmann 			return ERR_PTR(-EILSEQ);
110*07eb96a5SMarcel Holtmann 		}
111*07eb96a5SMarcel Holtmann 
112*07eb96a5SMarcel Holtmann 		if (skb->len == (&pkts[i])->hlen) {
113*07eb96a5SMarcel Holtmann 			u16 dlen;
114*07eb96a5SMarcel Holtmann 
115*07eb96a5SMarcel Holtmann 			switch ((&pkts[i])->lsize) {
116*07eb96a5SMarcel Holtmann 			case 0:
117*07eb96a5SMarcel Holtmann 				/* No variable data length */
118*07eb96a5SMarcel Holtmann 				dlen = 0;
119*07eb96a5SMarcel Holtmann 				break;
120*07eb96a5SMarcel Holtmann 			case 1:
121*07eb96a5SMarcel Holtmann 				/* Single octet variable length */
122*07eb96a5SMarcel Holtmann 				dlen = skb->data[(&pkts[i])->loff];
123*07eb96a5SMarcel Holtmann 				hci_skb_expect(skb) += dlen;
124*07eb96a5SMarcel Holtmann 
125*07eb96a5SMarcel Holtmann 				if (skb_tailroom(skb) < dlen) {
126*07eb96a5SMarcel Holtmann 					kfree_skb(skb);
127*07eb96a5SMarcel Holtmann 					return ERR_PTR(-EMSGSIZE);
128*07eb96a5SMarcel Holtmann 				}
129*07eb96a5SMarcel Holtmann 				break;
130*07eb96a5SMarcel Holtmann 			case 2:
131*07eb96a5SMarcel Holtmann 				/* Double octet variable length */
132*07eb96a5SMarcel Holtmann 				dlen = get_unaligned_le16(skb->data +
133*07eb96a5SMarcel Holtmann 							  (&pkts[i])->loff);
134*07eb96a5SMarcel Holtmann 				hci_skb_expect(skb) += dlen;
135*07eb96a5SMarcel Holtmann 
136*07eb96a5SMarcel Holtmann 				if (skb_tailroom(skb) < dlen) {
137*07eb96a5SMarcel Holtmann 					kfree_skb(skb);
138*07eb96a5SMarcel Holtmann 					return ERR_PTR(-EMSGSIZE);
139*07eb96a5SMarcel Holtmann 				}
140*07eb96a5SMarcel Holtmann 				break;
141*07eb96a5SMarcel Holtmann 			default:
142*07eb96a5SMarcel Holtmann 				/* Unsupported variable length */
143*07eb96a5SMarcel Holtmann 				kfree_skb(skb);
144*07eb96a5SMarcel Holtmann 				return ERR_PTR(-EILSEQ);
145*07eb96a5SMarcel Holtmann 			}
146*07eb96a5SMarcel Holtmann 
147*07eb96a5SMarcel Holtmann 			if (!dlen) {
148*07eb96a5SMarcel Holtmann 				/* No more data, complete frame */
149*07eb96a5SMarcel Holtmann 				(&pkts[i])->recv(hdev, skb);
150*07eb96a5SMarcel Holtmann 				skb = NULL;
151*07eb96a5SMarcel Holtmann 			}
152*07eb96a5SMarcel Holtmann 		} else {
153*07eb96a5SMarcel Holtmann 			/* Complete frame */
154*07eb96a5SMarcel Holtmann 			(&pkts[i])->recv(hdev, skb);
155*07eb96a5SMarcel Holtmann 			skb = NULL;
156*07eb96a5SMarcel Holtmann 		}
157*07eb96a5SMarcel Holtmann 	}
158*07eb96a5SMarcel Holtmann 
159*07eb96a5SMarcel Holtmann 	return skb;
160*07eb96a5SMarcel Holtmann }
161