]> Git Repo - linux.git/blob - drivers/bluetooth/h4_recv.h
crypto: akcipher - Drop sign/verify operations
[linux.git] / drivers / bluetooth / h4_recv.h
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 <asm/unaligned.h>
10
11 struct 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
48 static 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 }
This page took 0.040822 seconds and 4 git commands to generate.