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
;
78 skb_queue_purge(&h4
->txq
);
80 kfree_skb(h4
->rx_skb
);
88 /* Enqueue frame for transmittion (padding, crc, etc) */
89 static int h4_enqueue(struct hci_uart
*hu
, struct sk_buff
*skb
)
91 struct h4_struct
*h4
= hu
->priv
;
93 BT_DBG("hu %p skb %p", hu
, skb
);
95 /* Prepend skb with frame type */
96 memcpy(skb_push(skb
, 1), &hci_skb_pkt_type(skb
), 1);
97 skb_queue_tail(&h4
->txq
, skb
);
102 static const struct h4_recv_pkt h4_recv_pkts
[] = {
103 { H4_RECV_ACL
, .recv
= hci_recv_frame
},
104 { H4_RECV_SCO
, .recv
= hci_recv_frame
},
105 { H4_RECV_EVENT
, .recv
= hci_recv_frame
},
106 { H4_RECV_ISO
, .recv
= hci_recv_frame
},
110 static int h4_recv(struct hci_uart
*hu
, const void *data
, int count
)
112 struct h4_struct
*h4
= hu
->priv
;
114 if (!test_bit(HCI_UART_REGISTERED
, &hu
->flags
))
117 h4
->rx_skb
= h4_recv_buf(hu
->hdev
, h4
->rx_skb
, data
, count
,
118 h4_recv_pkts
, ARRAY_SIZE(h4_recv_pkts
));
119 if (IS_ERR(h4
->rx_skb
)) {
120 int err
= PTR_ERR(h4
->rx_skb
);
121 bt_dev_err(hu
->hdev
, "Frame reassembly failed (%d)", err
);
129 static struct sk_buff
*h4_dequeue(struct hci_uart
*hu
)
131 struct h4_struct
*h4
= hu
->priv
;
132 return skb_dequeue(&h4
->txq
);
135 static const struct hci_uart_proto h4p
= {
141 .enqueue
= h4_enqueue
,
142 .dequeue
= h4_dequeue
,
146 int __init
h4_init(void)
148 return hci_uart_register_proto(&h4p
);
151 int __exit
h4_deinit(void)
153 return hci_uart_unregister_proto(&h4p
);
156 struct sk_buff
*h4_recv_buf(struct hci_dev
*hdev
, struct sk_buff
*skb
,
157 const unsigned char *buffer
, int count
,
158 const struct h4_recv_pkt
*pkts
, int pkts_count
)
160 struct hci_uart
*hu
= hci_get_drvdata(hdev
);
161 u8 alignment
= hu
->alignment
? hu
->alignment
: 1;
163 /* Check for error from previous call */
170 /* remove padding bytes from buffer */
171 for (; hu
->padding
&& count
> 0; hu
->padding
--) {
179 for (i
= 0; i
< pkts_count
; i
++) {
180 if (buffer
[0] != (&pkts
[i
])->type
)
183 skb
= bt_skb_alloc((&pkts
[i
])->maxlen
,
186 return ERR_PTR(-ENOMEM
);
188 hci_skb_pkt_type(skb
) = (&pkts
[i
])->type
;
189 hci_skb_expect(skb
) = (&pkts
[i
])->hlen
;
193 /* Check for invalid packet type */
195 return ERR_PTR(-EILSEQ
);
201 len
= min_t(uint
, hci_skb_expect(skb
) - skb
->len
, count
);
202 skb_put_data(skb
, buffer
, len
);
207 /* Check for partial packet */
208 if (skb
->len
< hci_skb_expect(skb
))
211 for (i
= 0; i
< pkts_count
; i
++) {
212 if (hci_skb_pkt_type(skb
) == (&pkts
[i
])->type
)
216 if (i
>= pkts_count
) {
218 return ERR_PTR(-EILSEQ
);
221 if (skb
->len
== (&pkts
[i
])->hlen
) {
224 switch ((&pkts
[i
])->lsize
) {
226 /* No variable data length */
230 /* Single octet variable length */
231 dlen
= skb
->data
[(&pkts
[i
])->loff
];
232 hci_skb_expect(skb
) += dlen
;
234 if (skb_tailroom(skb
) < dlen
) {
236 return ERR_PTR(-EMSGSIZE
);
240 /* Double octet variable length */
241 dlen
= get_unaligned_le16(skb
->data
+
243 hci_skb_expect(skb
) += dlen
;
245 if (skb_tailroom(skb
) < dlen
) {
247 return ERR_PTR(-EMSGSIZE
);
251 /* Unsupported variable length */
253 return ERR_PTR(-EILSEQ
);
257 hu
->padding
= (skb
->len
- 1) % alignment
;
258 hu
->padding
= (alignment
- hu
->padding
) % alignment
;
260 /* No more data, complete frame */
261 (&pkts
[i
])->recv(hdev
, skb
);
265 hu
->padding
= (skb
->len
- 1) % alignment
;
266 hu
->padding
= (alignment
- hu
->padding
) % alignment
;
269 (&pkts
[i
])->recv(hdev
, skb
);
276 EXPORT_SYMBOL_GPL(h4_recv_buf
);