154 lines · c
1/* SPDX-License-Identifier: GPL-2.0-or-later */2/*3 *4 * Generic Bluetooth HCI UART driver5 *6 * Copyright (C) 2015-2018 Intel Corporation7 */8 9#include <linux/unaligned.h>10 11struct h4_recv_pkt {12 u8 type; /* Packet type */13 u8 hlen; /* Header length */14 u8 loff; /* Data length offset in header */15 u8 lsize; /* Data length field size */16 u16 maxlen; /* Max overall packet length */17 int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);18};19 20#define H4_RECV_ACL \21 .type = HCI_ACLDATA_PKT, \22 .hlen = HCI_ACL_HDR_SIZE, \23 .loff = 2, \24 .lsize = 2, \25 .maxlen = HCI_MAX_FRAME_SIZE \26 27#define H4_RECV_SCO \28 .type = HCI_SCODATA_PKT, \29 .hlen = HCI_SCO_HDR_SIZE, \30 .loff = 2, \31 .lsize = 1, \32 .maxlen = HCI_MAX_SCO_SIZE33 34#define H4_RECV_EVENT \35 .type = HCI_EVENT_PKT, \36 .hlen = HCI_EVENT_HDR_SIZE, \37 .loff = 1, \38 .lsize = 1, \39 .maxlen = HCI_MAX_EVENT_SIZE40 41#define H4_RECV_ISO \42 .type = HCI_ISODATA_PKT, \43 .hlen = HCI_ISO_HDR_SIZE, \44 .loff = 2, \45 .lsize = 2, \46 .maxlen = HCI_MAX_FRAME_SIZE47 48static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,49 struct sk_buff *skb,50 const unsigned char *buffer,51 int count,52 const struct h4_recv_pkt *pkts,53 int pkts_count)54{55 /* Check for error from previous call */56 if (IS_ERR(skb))57 skb = NULL;58 59 while (count) {60 int i, len;61 62 if (!skb) {63 for (i = 0; i < pkts_count; i++) {64 if (buffer[0] != (&pkts[i])->type)65 continue;66 67 skb = bt_skb_alloc((&pkts[i])->maxlen,68 GFP_ATOMIC);69 if (!skb)70 return ERR_PTR(-ENOMEM);71 72 hci_skb_pkt_type(skb) = (&pkts[i])->type;73 hci_skb_expect(skb) = (&pkts[i])->hlen;74 break;75 }76 77 /* Check for invalid packet type */78 if (!skb)79 return ERR_PTR(-EILSEQ);80 81 count -= 1;82 buffer += 1;83 }84 85 len = min_t(uint, hci_skb_expect(skb) - skb->len, count);86 skb_put_data(skb, buffer, len);87 88 count -= len;89 buffer += len;90 91 /* Check for partial packet */92 if (skb->len < hci_skb_expect(skb))93 continue;94 95 for (i = 0; i < pkts_count; i++) {96 if (hci_skb_pkt_type(skb) == (&pkts[i])->type)97 break;98 }99 100 if (i >= pkts_count) {101 kfree_skb(skb);102 return ERR_PTR(-EILSEQ);103 }104 105 if (skb->len == (&pkts[i])->hlen) {106 u16 dlen;107 108 switch ((&pkts[i])->lsize) {109 case 0:110 /* No variable data length */111 dlen = 0;112 break;113 case 1:114 /* Single octet variable length */115 dlen = skb->data[(&pkts[i])->loff];116 hci_skb_expect(skb) += dlen;117 118 if (skb_tailroom(skb) < dlen) {119 kfree_skb(skb);120 return ERR_PTR(-EMSGSIZE);121 }122 break;123 case 2:124 /* Double octet variable length */125 dlen = get_unaligned_le16(skb->data +126 (&pkts[i])->loff);127 hci_skb_expect(skb) += dlen;128 129 if (skb_tailroom(skb) < dlen) {130 kfree_skb(skb);131 return ERR_PTR(-EMSGSIZE);132 }133 break;134 default:135 /* Unsupported variable length */136 kfree_skb(skb);137 return ERR_PTR(-EILSEQ);138 }139 140 if (!dlen) {141 /* No more data, complete frame */142 (&pkts[i])->recv(hdev, skb);143 skb = NULL;144 }145 } else {146 /* Complete frame */147 (&pkts[i])->recv(hdev, skb);148 skb = NULL;149 }150 }151 152 return skb;153}154