Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 | 2 | /* |
1da177e4 | 3 | * |
0372a662 MH |
4 | * Bluetooth HCI UART driver |
5 | * | |
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> | |
1da177e4 | 9 | */ |
1da177e4 | 10 | |
1da177e4 LT |
11 | #include <linux/module.h> |
12 | ||
13 | #include <linux/kernel.h> | |
14 | #include <linux/init.h> | |
1da177e4 LT |
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> | |
20 | ||
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> | |
79b8df93 | 28 | #include <asm/unaligned.h> |
1da177e4 LT |
29 | |
30 | #include <net/bluetooth/bluetooth.h> | |
31 | #include <net/bluetooth/hci_core.h> | |
0372a662 | 32 | |
1da177e4 | 33 | #include "hci_uart.h" |
1da177e4 | 34 | |
0372a662 | 35 | struct h4_struct { |
c27799f9 | 36 | struct sk_buff *rx_skb; |
0372a662 MH |
37 | struct sk_buff_head txq; |
38 | }; | |
39 | ||
1da177e4 LT |
40 | /* Initialize protocol */ |
41 | static int h4_open(struct hci_uart *hu) | |
42 | { | |
43 | struct h4_struct *h4; | |
0372a662 | 44 | |
1da177e4 | 45 | BT_DBG("hu %p", hu); |
0372a662 | 46 | |
fdcd1661 | 47 | h4 = kzalloc(sizeof(*h4), GFP_KERNEL); |
1da177e4 LT |
48 | if (!h4) |
49 | return -ENOMEM; | |
0372a662 | 50 | |
1da177e4 LT |
51 | skb_queue_head_init(&h4->txq); |
52 | ||
53 | hu->priv = h4; | |
54 | return 0; | |
55 | } | |
56 | ||
57 | /* Flush protocol data */ | |
58 | static int h4_flush(struct hci_uart *hu) | |
59 | { | |
60 | struct h4_struct *h4 = hu->priv; | |
61 | ||
62 | BT_DBG("hu %p", hu); | |
0372a662 | 63 | |
1da177e4 | 64 | skb_queue_purge(&h4->txq); |
0372a662 | 65 | |
1da177e4 LT |
66 | return 0; |
67 | } | |
68 | ||
69 | /* Close protocol */ | |
70 | static int h4_close(struct hci_uart *hu) | |
71 | { | |
72 | struct h4_struct *h4 = hu->priv; | |
0372a662 | 73 | |
1da177e4 LT |
74 | BT_DBG("hu %p", hu); |
75 | ||
76 | skb_queue_purge(&h4->txq); | |
0372a662 | 77 | |
c27799f9 MH |
78 | kfree_skb(h4->rx_skb); |
79 | ||
1da177e4 LT |
80 | hu->priv = NULL; |
81 | kfree(h4); | |
0372a662 | 82 | |
1da177e4 LT |
83 | return 0; |
84 | } | |
85 | ||
6bd023c4 | 86 | /* Enqueue frame for transmission (padding, crc, etc) */ |
1da177e4 LT |
87 | static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) |
88 | { | |
89 | struct h4_struct *h4 = hu->priv; | |
90 | ||
91 | BT_DBG("hu %p skb %p", hu, skb); | |
92 | ||
93 | /* Prepend skb with frame type */ | |
618e8bc2 | 94 | memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); |
1da177e4 | 95 | skb_queue_tail(&h4->txq, skb); |
0372a662 | 96 | |
1da177e4 LT |
97 | return 0; |
98 | } | |
99 | ||
79b8df93 MH |
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 }, | |
ef564119 | 104 | { H4_RECV_ISO, .recv = hci_recv_frame }, |
79b8df93 MH |
105 | }; |
106 | ||
1da177e4 | 107 | /* Recv data */ |
9d1c40eb | 108 | static int h4_recv(struct hci_uart *hu, const void *data, int count) |
1da177e4 | 109 | { |
c27799f9 | 110 | struct h4_struct *h4 = hu->priv; |
b86ed368 | 111 | |
c2578202 CP |
112 | if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) |
113 | return -EUNATCH; | |
114 | ||
79b8df93 MH |
115 | h4->rx_skb = h4_recv_buf(hu->hdev, h4->rx_skb, data, count, |
116 | h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts)); | |
c27799f9 MH |
117 | if (IS_ERR(h4->rx_skb)) { |
118 | int err = PTR_ERR(h4->rx_skb); | |
2064ee33 | 119 | bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err); |
37134167 | 120 | h4->rx_skb = NULL; |
c27799f9 | 121 | return err; |
b86ed368 | 122 | } |
0372a662 | 123 | |
1da177e4 LT |
124 | return count; |
125 | } | |
126 | ||
127 | static struct sk_buff *h4_dequeue(struct hci_uart *hu) | |
128 | { | |
129 | struct h4_struct *h4 = hu->priv; | |
130 | return skb_dequeue(&h4->txq); | |
131 | } | |
132 | ||
4ee7ef19 | 133 | static const struct hci_uart_proto h4p = { |
0372a662 | 134 | .id = HCI_UART_H4, |
7c40fb8d | 135 | .name = "H4", |
0372a662 MH |
136 | .open = h4_open, |
137 | .close = h4_close, | |
138 | .recv = h4_recv, | |
139 | .enqueue = h4_enqueue, | |
140 | .dequeue = h4_dequeue, | |
141 | .flush = h4_flush, | |
1da177e4 | 142 | }; |
0372a662 | 143 | |
f2b94bb9 | 144 | int __init h4_init(void) |
1da177e4 | 145 | { |
01009eec | 146 | return hci_uart_register_proto(&h4p); |
1da177e4 LT |
147 | } |
148 | ||
f2b94bb9 | 149 | int __exit h4_deinit(void) |
1da177e4 LT |
150 | { |
151 | return hci_uart_unregister_proto(&h4p); | |
152 | } | |
e1a38d70 MH |
153 | |
154 | struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, | |
79b8df93 MH |
155 | const unsigned char *buffer, int count, |
156 | const struct h4_recv_pkt *pkts, int pkts_count) | |
e1a38d70 | 157 | { |
aeac3014 | 158 | struct hci_uart *hu = hci_get_drvdata(hdev); |
fb776481 | 159 | u8 alignment = hu->alignment ? hu->alignment : 1; |
aeac3014 | 160 | |
1dc2d785 MJ |
161 | /* Check for error from previous call */ |
162 | if (IS_ERR(skb)) | |
163 | skb = NULL; | |
164 | ||
e1a38d70 | 165 | while (count) { |
79b8df93 | 166 | int i, len; |
e1a38d70 | 167 | |
aeac3014 SR |
168 | /* remove padding bytes from buffer */ |
169 | for (; hu->padding && count > 0; hu->padding--) { | |
170 | count--; | |
171 | buffer++; | |
172 | } | |
173 | if (!count) | |
174 | break; | |
175 | ||
e1a38d70 | 176 | if (!skb) { |
79b8df93 MH |
177 | for (i = 0; i < pkts_count; i++) { |
178 | if (buffer[0] != (&pkts[i])->type) | |
179 | continue; | |
e1a38d70 | 180 | |
79b8df93 | 181 | skb = bt_skb_alloc((&pkts[i])->maxlen, |
e1a38d70 MH |
182 | GFP_ATOMIC); |
183 | if (!skb) | |
184 | return ERR_PTR(-ENOMEM); | |
185 | ||
618e8bc2 MH |
186 | hci_skb_pkt_type(skb) = (&pkts[i])->type; |
187 | hci_skb_expect(skb) = (&pkts[i])->hlen; | |
e1a38d70 | 188 | break; |
79b8df93 | 189 | } |
e1a38d70 | 190 | |
79b8df93 MH |
191 | /* Check for invalid packet type */ |
192 | if (!skb) | |
e1a38d70 | 193 | return ERR_PTR(-EILSEQ); |
e1a38d70 MH |
194 | |
195 | count -= 1; | |
196 | buffer += 1; | |
197 | } | |
198 | ||
618e8bc2 | 199 | len = min_t(uint, hci_skb_expect(skb) - skb->len, count); |
59ae1d12 | 200 | skb_put_data(skb, buffer, len); |
e1a38d70 MH |
201 | |
202 | count -= len; | |
203 | buffer += len; | |
e1a38d70 | 204 | |
79b8df93 | 205 | /* Check for partial packet */ |
618e8bc2 | 206 | if (skb->len < hci_skb_expect(skb)) |
79b8df93 MH |
207 | continue; |
208 | ||
209 | for (i = 0; i < pkts_count; i++) { | |
618e8bc2 | 210 | if (hci_skb_pkt_type(skb) == (&pkts[i])->type) |
79b8df93 MH |
211 | break; |
212 | } | |
213 | ||
214 | if (i >= pkts_count) { | |
215 | kfree_skb(skb); | |
216 | return ERR_PTR(-EILSEQ); | |
217 | } | |
e1a38d70 | 218 | |
79b8df93 MH |
219 | if (skb->len == (&pkts[i])->hlen) { |
220 | u16 dlen; | |
e1a38d70 | 221 | |
79b8df93 MH |
222 | switch ((&pkts[i])->lsize) { |
223 | case 0: | |
224 | /* No variable data length */ | |
e5499167 | 225 | dlen = 0; |
79b8df93 MH |
226 | break; |
227 | case 1: | |
228 | /* Single octet variable length */ | |
229 | dlen = skb->data[(&pkts[i])->loff]; | |
618e8bc2 | 230 | hci_skb_expect(skb) += dlen; |
e1a38d70 | 231 | |
79b8df93 | 232 | if (skb_tailroom(skb) < dlen) { |
e1a38d70 MH |
233 | kfree_skb(skb); |
234 | return ERR_PTR(-EMSGSIZE); | |
235 | } | |
79b8df93 MH |
236 | break; |
237 | case 2: | |
238 | /* Double octet variable length */ | |
239 | dlen = get_unaligned_le16(skb->data + | |
240 | (&pkts[i])->loff); | |
618e8bc2 | 241 | hci_skb_expect(skb) += dlen; |
e1a38d70 | 242 | |
79b8df93 | 243 | if (skb_tailroom(skb) < dlen) { |
e1a38d70 MH |
244 | kfree_skb(skb); |
245 | return ERR_PTR(-EMSGSIZE); | |
246 | } | |
79b8df93 MH |
247 | break; |
248 | default: | |
249 | /* Unsupported variable length */ | |
250 | kfree_skb(skb); | |
251 | return ERR_PTR(-EILSEQ); | |
e1a38d70 | 252 | } |
e5499167 LP |
253 | |
254 | if (!dlen) { | |
dd2ac1d6 | 255 | hu->padding = (skb->len + 1) % alignment; |
aeac3014 SR |
256 | hu->padding = (alignment - hu->padding) % alignment; |
257 | ||
e5499167 LP |
258 | /* No more data, complete frame */ |
259 | (&pkts[i])->recv(hdev, skb); | |
260 | skb = NULL; | |
261 | } | |
79b8df93 | 262 | } else { |
dd2ac1d6 | 263 | hu->padding = (skb->len + 1) % alignment; |
aeac3014 SR |
264 | hu->padding = (alignment - hu->padding) % alignment; |
265 | ||
e1a38d70 | 266 | /* Complete frame */ |
79b8df93 | 267 | (&pkts[i])->recv(hdev, skb); |
e1a38d70 MH |
268 | skb = NULL; |
269 | } | |
270 | } | |
271 | ||
272 | return skb; | |
273 | } | |
943cc592 | 274 | EXPORT_SYMBOL_GPL(h4_recv_buf); |