aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth/hci_h4.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/hci_h4.c')
-rw-r--r--drivers/bluetooth/hci_h4.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 97a5df4941b4..09270bc26654 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -161,3 +161,101 @@ int __exit h4_deinit(void)
161{ 161{
162 return hci_uart_unregister_proto(&h4p); 162 return hci_uart_unregister_proto(&h4p);
163} 163}
164
165struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
166 const unsigned char *buffer, int count)
167{
168 while (count) {
169 int len;
170
171 if (!skb) {
172 switch (buffer[0]) {
173 case HCI_ACLDATA_PKT:
174 skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE,
175 GFP_ATOMIC);
176 if (!skb)
177 return ERR_PTR(-ENOMEM);
178
179 bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
180 bt_cb(skb)->expect = HCI_ACL_HDR_SIZE;
181 break;
182 case HCI_SCODATA_PKT:
183 skb = bt_skb_alloc(HCI_MAX_SCO_SIZE,
184 GFP_ATOMIC);
185 if (!skb)
186 return ERR_PTR(-ENOMEM);
187
188 bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
189 bt_cb(skb)->expect = HCI_SCO_HDR_SIZE;
190 break;
191 case HCI_EVENT_PKT:
192 skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE,
193 GFP_ATOMIC);
194 if (!skb)
195 return ERR_PTR(-ENOMEM);
196
197 bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
198 bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE;
199 break;
200 default:
201 return ERR_PTR(-EILSEQ);
202 }
203
204 count -= 1;
205 buffer += 1;
206 }
207
208 len = min_t(uint, bt_cb(skb)->expect, count);
209 memcpy(skb_put(skb, len), buffer, len);
210
211 count -= len;
212 buffer += len;
213 bt_cb(skb)->expect -= len;
214
215 switch (bt_cb(skb)->pkt_type) {
216 case HCI_ACLDATA_PKT:
217 if (skb->len == HCI_ACL_HDR_SIZE) {
218 __le16 dlen = hci_acl_hdr(skb)->dlen;
219
220 /* Complete ACL header */
221 bt_cb(skb)->expect = __le16_to_cpu(dlen);
222
223 if (skb_tailroom(skb) < bt_cb(skb)->expect) {
224 kfree_skb(skb);
225 return ERR_PTR(-EMSGSIZE);
226 }
227 }
228 break;
229 case HCI_SCODATA_PKT:
230 if (skb->len == HCI_SCO_HDR_SIZE) {
231 /* Complete SCO header */
232 bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen;
233
234 if (skb_tailroom(skb) < bt_cb(skb)->expect) {
235 kfree_skb(skb);
236 return ERR_PTR(-EMSGSIZE);
237 }
238 }
239 break;
240 case HCI_EVENT_PKT:
241 if (skb->len == HCI_EVENT_HDR_SIZE) {
242 /* Complete event header */
243 bt_cb(skb)->expect = hci_event_hdr(skb)->plen;
244
245 if (skb_tailroom(skb) < bt_cb(skb)->expect) {
246 kfree_skb(skb);
247 return ERR_PTR(-EMSGSIZE);
248 }
249 }
250 break;
251 }
252
253 if (bt_cb(skb)->expect == 0) {
254 /* Complete frame */
255 hci_recv_frame(hdev, skb);
256 skb = NULL;
257 }
258 }
259
260 return skb;
261}