1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Bluetooth HCI UART driver
6 * Copyright (C) 2000-2001 Qualcomm Incorporated
7 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
8 * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
11 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/types.h>
16 #include <linux/fcntl.h>
17 #include <linux/interrupt.h>
18 #include <linux/ptrace.h>
19 #include <linux/poll.h>
21 #include <linux/slab.h>
22 #include <linux/tty.h>
23 #include <linux/errno.h>
24 #include <linux/string.h>
25 #include <linux/signal.h>
26 #include <linux/ioctl.h>
27 #include <linux/skbuff.h>
28 #include <asm/unaligned.h>
30 #include <net/bluetooth/bluetooth.h>
31 #include <net/bluetooth/hci_core.h>
36 struct sk_buff
*rx_skb
;
37 struct sk_buff_head txq
;
40 /* Initialize protocol */
41 static int h4_open(struct hci_uart
*hu
)
47 h4
= kzalloc(sizeof(*h4
), GFP_KERNEL
);
51 skb_queue_head_init(&h4
->txq
);
57 /* Flush protocol data */
58 static int h4_flush(struct hci_uart
*hu
)
60 struct h4_struct
*h4
= hu
->priv
;
64 skb_queue_purge(&h4
->txq
);
70 static int h4_close(struct hci_uart
*hu
)
72 struct h4_struct
*h4
= hu
->priv
;
76 skb_queue_purge(&h4
->txq
);
78 kfree_skb(h4
->rx_skb
);
86 /* Enqueue frame for transmission (padding, crc, etc) */
87 static int h4_enqueue(struct hci_uart
*hu
, struct sk_buff
*skb
)
89 struct h4_struct
*h4
= hu
->priv
;
91 BT_DBG("hu %p skb %p", hu
, skb
);
93 /* Prepend skb with frame type */
94 memcpy(skb_push(skb
, 1), &hci_skb_pkt_type(skb
), 1);
95 skb_queue_tail(&h4
->txq
, skb
);
100 static const struct h4_recv_pkt h4_recv_pkts
[] = {
101 { H4_RECV_ACL
, .recv
= hci_recv_frame
},
102 { H4_RECV_SCO
, .recv
= hci_recv_frame
},
103 { H4_RECV_EVENT
, .recv
= hci_recv_frame
},
104 { H4_RECV_ISO
, .recv
= hci_recv_frame
},
108 static int h4_recv(struct hci_uart
*hu
, const void *data
, int count
)
110 struct h4_struct
*h4
= hu
->priv
;
112 if (!test_bit(HCI_UART_REGISTERED
, &hu
->flags
))
115 h4
->rx_skb
= h4_recv_buf(hu
->hdev
, h4
->rx_skb
, data
, count
,
116 h4_recv_pkts
, ARRAY_SIZE(h4_recv_pkts
));
117 if (IS_ERR(h4
->rx_skb
)) {
118 int err
= PTR_ERR(h4
->rx_skb
);
119 bt_dev_err(hu
->hdev
, "Frame reassembly failed (%d)", err
);
127 static struct sk_buff
*h4_dequeue(struct hci_uart
*hu
)
129 struct h4_struct
*h4
= hu
->priv
;
130 return skb_dequeue(&h4
->txq
);
133 static const struct hci_uart_proto h4p
= {
139 .enqueue
= h4_enqueue
,
140 .dequeue
= h4_dequeue
,
144 int __init
h4_init(void)
146 return hci_uart_register_proto(&h4p
);
149 int __exit
h4_deinit(void)
151 return hci_uart_unregister_proto(&h4p
);
154 struct sk_buff
*h4_recv_buf(struct hci_dev
*hdev
, struct sk_buff
*skb
,
155 const unsigned char *buffer
, int count
,
156 const struct h4_recv_pkt
*pkts
, int pkts_count
)
158 struct hci_uart
*hu
= hci_get_drvdata(hdev
);
159 u8 alignment
= hu
->alignment
? hu
->alignment
: 1;
161 /* Check for error from previous call */
168 /* remove padding bytes from buffer */
169 for (; hu
->padding
&& count
> 0; hu
->padding
--) {
177 for (i
= 0; i
< pkts_count
; i
++) {
178 if (buffer
[0] != (&pkts
[i
])->type
)
181 skb
= bt_skb_alloc((&pkts
[i
])->maxlen
,
184 return ERR_PTR(-ENOMEM
);
186 hci_skb_pkt_type(skb
) = (&pkts
[i
])->type
;
187 hci_skb_expect(skb
) = (&pkts
[i
])->hlen
;
191 /* Check for invalid packet type */
193 return ERR_PTR(-EILSEQ
);
199 len
= min_t(uint
, hci_skb_expect(skb
) - skb
->len
, count
);
200 skb_put_data(skb
, buffer
, len
);
205 /* Check for partial packet */
206 if (skb
->len
< hci_skb_expect(skb
))
209 for (i
= 0; i
< pkts_count
; i
++) {
210 if (hci_skb_pkt_type(skb
) == (&pkts
[i
])->type
)
214 if (i
>= pkts_count
) {
216 return ERR_PTR(-EILSEQ
);
219 if (skb
->len
== (&pkts
[i
])->hlen
) {
222 switch ((&pkts
[i
])->lsize
) {
224 /* No variable data length */
228 /* Single octet variable length */
229 dlen
= skb
->data
[(&pkts
[i
])->loff
];
230 hci_skb_expect(skb
) += dlen
;
232 if (skb_tailroom(skb
) < dlen
) {
234 return ERR_PTR(-EMSGSIZE
);
238 /* Double octet variable length */
239 dlen
= get_unaligned_le16(skb
->data
+
241 hci_skb_expect(skb
) += dlen
;
243 if (skb_tailroom(skb
) < dlen
) {
245 return ERR_PTR(-EMSGSIZE
);
249 /* Unsupported variable length */
251 return ERR_PTR(-EILSEQ
);
255 hu
->padding
= (skb
->len
- 1) % alignment
;
256 hu
->padding
= (alignment
- hu
->padding
) % alignment
;
258 /* No more data, complete frame */
259 (&pkts
[i
])->recv(hdev
, skb
);
263 hu
->padding
= (skb
->len
- 1) % alignment
;
264 hu
->padding
= (alignment
- hu
->padding
) % alignment
;
267 (&pkts
[i
])->recv(hdev
, skb
);
274 EXPORT_SYMBOL_GPL(h4_recv_buf
);