0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <asm/unaligned.h>
0010
0011 struct h4_recv_pkt {
0012 u8 type;
0013 u8 hlen;
0014 u8 loff;
0015 u8 lsize;
0016 u16 maxlen;
0017 int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
0018 };
0019
0020 #define H4_RECV_ACL \
0021 .type = HCI_ACLDATA_PKT, \
0022 .hlen = HCI_ACL_HDR_SIZE, \
0023 .loff = 2, \
0024 .lsize = 2, \
0025 .maxlen = HCI_MAX_FRAME_SIZE \
0026
0027 #define H4_RECV_SCO \
0028 .type = HCI_SCODATA_PKT, \
0029 .hlen = HCI_SCO_HDR_SIZE, \
0030 .loff = 2, \
0031 .lsize = 1, \
0032 .maxlen = HCI_MAX_SCO_SIZE
0033
0034 #define H4_RECV_EVENT \
0035 .type = HCI_EVENT_PKT, \
0036 .hlen = HCI_EVENT_HDR_SIZE, \
0037 .loff = 1, \
0038 .lsize = 1, \
0039 .maxlen = HCI_MAX_EVENT_SIZE
0040
0041 static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,
0042 struct sk_buff *skb,
0043 const unsigned char *buffer,
0044 int count,
0045 const struct h4_recv_pkt *pkts,
0046 int pkts_count)
0047 {
0048
0049 if (IS_ERR(skb))
0050 skb = NULL;
0051
0052 while (count) {
0053 int i, len;
0054
0055 if (!skb) {
0056 for (i = 0; i < pkts_count; i++) {
0057 if (buffer[0] != (&pkts[i])->type)
0058 continue;
0059
0060 skb = bt_skb_alloc((&pkts[i])->maxlen,
0061 GFP_ATOMIC);
0062 if (!skb)
0063 return ERR_PTR(-ENOMEM);
0064
0065 hci_skb_pkt_type(skb) = (&pkts[i])->type;
0066 hci_skb_expect(skb) = (&pkts[i])->hlen;
0067 break;
0068 }
0069
0070
0071 if (!skb)
0072 return ERR_PTR(-EILSEQ);
0073
0074 count -= 1;
0075 buffer += 1;
0076 }
0077
0078 len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
0079 skb_put_data(skb, buffer, len);
0080
0081 count -= len;
0082 buffer += len;
0083
0084
0085 if (skb->len < hci_skb_expect(skb))
0086 continue;
0087
0088 for (i = 0; i < pkts_count; i++) {
0089 if (hci_skb_pkt_type(skb) == (&pkts[i])->type)
0090 break;
0091 }
0092
0093 if (i >= pkts_count) {
0094 kfree_skb(skb);
0095 return ERR_PTR(-EILSEQ);
0096 }
0097
0098 if (skb->len == (&pkts[i])->hlen) {
0099 u16 dlen;
0100
0101 switch ((&pkts[i])->lsize) {
0102 case 0:
0103
0104 dlen = 0;
0105 break;
0106 case 1:
0107
0108 dlen = skb->data[(&pkts[i])->loff];
0109 hci_skb_expect(skb) += dlen;
0110
0111 if (skb_tailroom(skb) < dlen) {
0112 kfree_skb(skb);
0113 return ERR_PTR(-EMSGSIZE);
0114 }
0115 break;
0116 case 2:
0117
0118 dlen = get_unaligned_le16(skb->data +
0119 (&pkts[i])->loff);
0120 hci_skb_expect(skb) += dlen;
0121
0122 if (skb_tailroom(skb) < dlen) {
0123 kfree_skb(skb);
0124 return ERR_PTR(-EMSGSIZE);
0125 }
0126 break;
0127 default:
0128
0129 kfree_skb(skb);
0130 return ERR_PTR(-EILSEQ);
0131 }
0132
0133 if (!dlen) {
0134
0135 (&pkts[i])->recv(hdev, skb);
0136 skb = NULL;
0137 }
0138 } else {
0139
0140 (&pkts[i])->recv(hdev, skb);
0141 skb = NULL;
0142 }
0143 }
0144
0145 return skb;
0146 }