Skip to content

Commit 79b8df9

Browse files
committed
Bluetooth: hci_uart: Provide generic H:4 receive framework
Future H:4 based UART drivers require custom packet types and custom receive functions. To support this, extended the h4_recv_buf function with a packet definition table. For the default H:4 packets types of ACL data, SCO data and events, provide helpers to reduce the amount of code duplication. Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
1 parent 9a0bb57 commit 79b8df9

File tree

4 files changed

+110
-60
lines changed

4 files changed

+110
-60
lines changed

drivers/bluetooth/hci_ath.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,19 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu)
190190
return skb_dequeue(&ath->txq);
191191
}
192192

193+
static const struct h4_recv_pkt ath_recv_pkts[] = {
194+
{ H4_RECV_ACL, .recv = hci_recv_frame },
195+
{ H4_RECV_SCO, .recv = hci_recv_frame },
196+
{ H4_RECV_EVENT, .recv = hci_recv_frame },
197+
};
198+
193199
/* Recv data */
194200
static int ath_recv(struct hci_uart *hu, const void *data, int count)
195201
{
196202
struct ath_struct *ath = hu->priv;
197203

198-
ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count);
204+
ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count,
205+
ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts));
199206
if (IS_ERR(ath->rx_skb)) {
200207
int err = PTR_ERR(ath->rx_skb);
201208
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);

drivers/bluetooth/hci_bcm.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,21 @@ static int bcm_setup(struct hci_uart *hu)
8686
return btbcm_setup_patchram(hu->hdev);
8787
}
8888

89+
static const struct h4_recv_pkt bcm_recv_pkts[] = {
90+
{ H4_RECV_ACL, .recv = hci_recv_frame },
91+
{ H4_RECV_SCO, .recv = hci_recv_frame },
92+
{ H4_RECV_EVENT, .recv = hci_recv_frame },
93+
};
94+
8995
static int bcm_recv(struct hci_uart *hu, const void *data, int count)
9096
{
9197
struct bcm_data *bcm = hu->priv;
9298

9399
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
94100
return -EUNATCH;
95101

96-
bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count);
102+
bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count,
103+
bcm_recv_pkts, ARRAY_SIZE(bcm_recv_pkts));
97104
if (IS_ERR(bcm->rx_skb)) {
98105
int err = PTR_ERR(bcm->rx_skb);
99106
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);

drivers/bluetooth/hci_h4.c

+62-57
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <linux/signal.h>
4141
#include <linux/ioctl.h>
4242
#include <linux/skbuff.h>
43+
#include <asm/unaligned.h>
4344

4445
#include <net/bluetooth/bluetooth.h>
4546
#include <net/bluetooth/hci_core.h>
@@ -113,6 +114,12 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
113114
return 0;
114115
}
115116

117+
static const struct h4_recv_pkt h4_recv_pkts[] = {
118+
{ H4_RECV_ACL, .recv = hci_recv_frame },
119+
{ H4_RECV_SCO, .recv = hci_recv_frame },
120+
{ H4_RECV_EVENT, .recv = hci_recv_frame },
121+
};
122+
116123
/* Recv data */
117124
static int h4_recv(struct hci_uart *hu, const void *data, int count)
118125
{
@@ -121,7 +128,8 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
121128
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
122129
return -EUNATCH;
123130

124-
h4->rx_skb = h4_recv_buf(hu->hdev, h4->rx_skb, data, count);
131+
h4->rx_skb = h4_recv_buf(hu->hdev, h4->rx_skb, data, count,
132+
h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
125133
if (IS_ERR(h4->rx_skb)) {
126134
int err = PTR_ERR(h4->rx_skb);
127135
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
@@ -159,96 +167,93 @@ int __exit h4_deinit(void)
159167
}
160168

161169
struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
162-
const unsigned char *buffer, int count)
170+
const unsigned char *buffer, int count,
171+
const struct h4_recv_pkt *pkts, int pkts_count)
163172
{
164173
while (count) {
165-
int len;
174+
int i, len;
166175

167176
if (!skb) {
168-
switch (buffer[0]) {
169-
case HCI_ACLDATA_PKT:
170-
skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE,
171-
GFP_ATOMIC);
172-
if (!skb)
173-
return ERR_PTR(-ENOMEM);
177+
for (i = 0; i < pkts_count; i++) {
178+
if (buffer[0] != (&pkts[i])->type)
179+
continue;
174180

175-
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
176-
bt_cb(skb)->expect = HCI_ACL_HDR_SIZE;
177-
break;
178-
case HCI_SCODATA_PKT:
179-
skb = bt_skb_alloc(HCI_MAX_SCO_SIZE,
181+
skb = bt_skb_alloc((&pkts[i])->maxlen,
180182
GFP_ATOMIC);
181183
if (!skb)
182184
return ERR_PTR(-ENOMEM);
183185

184-
bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
185-
bt_cb(skb)->expect = HCI_SCO_HDR_SIZE;
186+
bt_cb(skb)->pkt_type = (&pkts[i])->type;
187+
bt_cb(skb)->expect = (&pkts[i])->hlen;
186188
break;
187-
case HCI_EVENT_PKT:
188-
skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE,
189-
GFP_ATOMIC);
190-
if (!skb)
191-
return ERR_PTR(-ENOMEM);
189+
}
192190

193-
bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
194-
bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE;
195-
break;
196-
default:
191+
/* Check for invalid packet type */
192+
if (!skb)
197193
return ERR_PTR(-EILSEQ);
198-
}
199194

200195
count -= 1;
201196
buffer += 1;
202197
}
203198

204-
len = min_t(uint, bt_cb(skb)->expect, count);
199+
len = min_t(uint, bt_cb(skb)->expect - skb->len, count);
205200
memcpy(skb_put(skb, len), buffer, len);
206201

207202
count -= len;
208203
buffer += len;
209-
bt_cb(skb)->expect -= len;
210204

211-
switch (bt_cb(skb)->pkt_type) {
212-
case HCI_ACLDATA_PKT:
213-
if (skb->len == HCI_ACL_HDR_SIZE) {
214-
__le16 dlen = hci_acl_hdr(skb)->dlen;
205+
/* Check for partial packet */
206+
if (skb->len < bt_cb(skb)->expect)
207+
continue;
208+
209+
for (i = 0; i < pkts_count; i++) {
210+
if (bt_cb(skb)->pkt_type == (&pkts[i])->type)
211+
break;
212+
}
213+
214+
if (i >= pkts_count) {
215+
kfree_skb(skb);
216+
return ERR_PTR(-EILSEQ);
217+
}
215218

216-
/* Complete ACL header */
217-
bt_cb(skb)->expect = __le16_to_cpu(dlen);
219+
if (skb->len == (&pkts[i])->hlen) {
220+
u16 dlen;
218221

219-
if (skb_tailroom(skb) < bt_cb(skb)->expect) {
220-
kfree_skb(skb);
221-
return ERR_PTR(-EMSGSIZE);
222-
}
223-
}
224-
break;
225-
case HCI_SCODATA_PKT:
226-
if (skb->len == HCI_SCO_HDR_SIZE) {
227-
/* Complete SCO header */
228-
bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen;
222+
switch ((&pkts[i])->lsize) {
223+
case 0:
224+
/* No variable data length */
225+
(&pkts[i])->recv(hdev, skb);
226+
skb = NULL;
227+
break;
228+
case 1:
229+
/* Single octet variable length */
230+
dlen = skb->data[(&pkts[i])->loff];
231+
bt_cb(skb)->expect += dlen;
229232

230-
if (skb_tailroom(skb) < bt_cb(skb)->expect) {
233+
if (skb_tailroom(skb) < dlen) {
231234
kfree_skb(skb);
232235
return ERR_PTR(-EMSGSIZE);
233236
}
234-
}
235-
break;
236-
case HCI_EVENT_PKT:
237-
if (skb->len == HCI_EVENT_HDR_SIZE) {
238-
/* Complete event header */
239-
bt_cb(skb)->expect = hci_event_hdr(skb)->plen;
237+
break;
238+
case 2:
239+
/* Double octet variable length */
240+
dlen = get_unaligned_le16(skb->data +
241+
(&pkts[i])->loff);
242+
bt_cb(skb)->expect += dlen;
240243

241-
if (skb_tailroom(skb) < bt_cb(skb)->expect) {
244+
if (skb_tailroom(skb) < dlen) {
242245
kfree_skb(skb);
243246
return ERR_PTR(-EMSGSIZE);
244247
}
248+
break;
249+
default:
250+
/* Unsupported variable length */
251+
kfree_skb(skb);
252+
return ERR_PTR(-EILSEQ);
245253
}
246-
break;
247-
}
248-
249-
if (bt_cb(skb)->expect == 0) {
254+
} else {
250255
/* Complete frame */
251-
hci_recv_frame(hdev, skb);
256+
(&pkts[i])->recv(hdev, skb);
252257
skb = NULL;
253258
}
254259
}

drivers/bluetooth/hci_uart.h

+32-1
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,39 @@ int hci_uart_init_ready(struct hci_uart *hu);
101101
int h4_init(void);
102102
int h4_deinit(void);
103103

104+
struct h4_recv_pkt {
105+
u8 type; /* Packet type */
106+
u8 hlen; /* Header length */
107+
u8 loff; /* Data length offset in header */
108+
u8 lsize; /* Data length field size */
109+
u16 maxlen; /* Max overall packet length */
110+
int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
111+
};
112+
113+
#define H4_RECV_ACL \
114+
.type = HCI_ACLDATA_PKT, \
115+
.hlen = HCI_ACL_HDR_SIZE, \
116+
.loff = 2, \
117+
.lsize = 2, \
118+
.maxlen = HCI_MAX_FRAME_SIZE \
119+
120+
#define H4_RECV_SCO \
121+
.type = HCI_SCODATA_PKT, \
122+
.hlen = HCI_SCO_HDR_SIZE, \
123+
.loff = 2, \
124+
.lsize = 1, \
125+
.maxlen = HCI_MAX_SCO_SIZE
126+
127+
#define H4_RECV_EVENT \
128+
.type = HCI_EVENT_PKT, \
129+
.hlen = HCI_EVENT_HDR_SIZE, \
130+
.loff = 1, \
131+
.lsize = 1, \
132+
.maxlen = HCI_MAX_EVENT_SIZE
133+
104134
struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
105-
const unsigned char *buffer, int count);
135+
const unsigned char *buffer, int count,
136+
const struct h4_recv_pkt *pkts, int pkts_count);
106137
#endif
107138

108139
#ifdef CONFIG_BT_HCIUART_BCSP

0 commit comments

Comments
 (0)