root/drivers/bluetooth/h4_recv.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. h4_recv_buf

   1 /* SPDX-License-Identifier: GPL-2.0-or-later */
   2 /*
   3  *
   4  *  Generic Bluetooth HCI UART driver
   5  *
   6  *  Copyright (C) 2015-2018  Intel Corporation
   7  */
   8 
   9 #include <asm/unaligned.h>
  10 
  11 struct 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_SIZE
  33 
  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_SIZE
  40 
  41 static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,
  42                                           struct sk_buff *skb,
  43                                           const unsigned char *buffer,
  44                                           int count,
  45                                           const struct h4_recv_pkt *pkts,
  46                                           int pkts_count)
  47 {
  48         /* Check for error from previous call */
  49         if (IS_ERR(skb))
  50                 skb = NULL;
  51 
  52         while (count) {
  53                 int i, len;
  54 
  55                 if (!skb) {
  56                         for (i = 0; i < pkts_count; i++) {
  57                                 if (buffer[0] != (&pkts[i])->type)
  58                                         continue;
  59 
  60                                 skb = bt_skb_alloc((&pkts[i])->maxlen,
  61                                                    GFP_ATOMIC);
  62                                 if (!skb)
  63                                         return ERR_PTR(-ENOMEM);
  64 
  65                                 hci_skb_pkt_type(skb) = (&pkts[i])->type;
  66                                 hci_skb_expect(skb) = (&pkts[i])->hlen;
  67                                 break;
  68                         }
  69 
  70                         /* Check for invalid packet type */
  71                         if (!skb)
  72                                 return ERR_PTR(-EILSEQ);
  73 
  74                         count -= 1;
  75                         buffer += 1;
  76                 }
  77 
  78                 len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
  79                 skb_put_data(skb, buffer, len);
  80 
  81                 count -= len;
  82                 buffer += len;
  83 
  84                 /* Check for partial packet */
  85                 if (skb->len < hci_skb_expect(skb))
  86                         continue;
  87 
  88                 for (i = 0; i < pkts_count; i++) {
  89                         if (hci_skb_pkt_type(skb) == (&pkts[i])->type)
  90                                 break;
  91                 }
  92 
  93                 if (i >= pkts_count) {
  94                         kfree_skb(skb);
  95                         return ERR_PTR(-EILSEQ);
  96                 }
  97 
  98                 if (skb->len == (&pkts[i])->hlen) {
  99                         u16 dlen;
 100 
 101                         switch ((&pkts[i])->lsize) {
 102                         case 0:
 103                                 /* No variable data length */
 104                                 dlen = 0;
 105                                 break;
 106                         case 1:
 107                                 /* Single octet variable length */
 108                                 dlen = skb->data[(&pkts[i])->loff];
 109                                 hci_skb_expect(skb) += dlen;
 110 
 111                                 if (skb_tailroom(skb) < dlen) {
 112                                         kfree_skb(skb);
 113                                         return ERR_PTR(-EMSGSIZE);
 114                                 }
 115                                 break;
 116                         case 2:
 117                                 /* Double octet variable length */
 118                                 dlen = get_unaligned_le16(skb->data +
 119                                                           (&pkts[i])->loff);
 120                                 hci_skb_expect(skb) += dlen;
 121 
 122                                 if (skb_tailroom(skb) < dlen) {
 123                                         kfree_skb(skb);
 124                                         return ERR_PTR(-EMSGSIZE);
 125                                 }
 126                                 break;
 127                         default:
 128                                 /* Unsupported variable length */
 129                                 kfree_skb(skb);
 130                                 return ERR_PTR(-EILSEQ);
 131                         }
 132 
 133                         if (!dlen) {
 134                                 /* No more data, complete frame */
 135                                 (&pkts[i])->recv(hdev, skb);
 136                                 skb = NULL;
 137                         }
 138                 } else {
 139                         /* Complete frame */
 140                         (&pkts[i])->recv(hdev, skb);
 141                         skb = NULL;
 142                 }
 143         }
 144 
 145         return skb;
 146 }

/* [<][>][^][v][top][bottom][index][help] */