static inline int bfusb_recv_block()

in bfusb.c [245:331]


static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned char *buf, int len)
{
	BT_DBG("bfusb %p hdr 0x%02x data %p len %d", data, hdr, buf, len);

	if (hdr & 0x10) {
		bt_dev_err(data->hdev, "error in block");
		kfree_skb(data->reassembly);
		data->reassembly = NULL;
		return -EIO;
	}

	if (hdr & 0x04) {
		struct sk_buff *skb;
		unsigned char pkt_type;
		int pkt_len = 0;

		if (data->reassembly) {
			bt_dev_err(data->hdev, "unexpected start block");
			kfree_skb(data->reassembly);
			data->reassembly = NULL;
		}

		if (len < 1) {
			bt_dev_err(data->hdev, "no packet type found");
			return -EPROTO;
		}

		pkt_type = *buf++; len--;

		switch (pkt_type) {
		case HCI_EVENT_PKT:
			if (len >= HCI_EVENT_HDR_SIZE) {
				struct hci_event_hdr *hdr = (struct hci_event_hdr *) buf;
				pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
			} else {
				bt_dev_err(data->hdev, "event block is too short");
				return -EILSEQ;
			}
			break;

		case HCI_ACLDATA_PKT:
			if (len >= HCI_ACL_HDR_SIZE) {
				struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) buf;
				pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
			} else {
				bt_dev_err(data->hdev, "data block is too short");
				return -EILSEQ;
			}
			break;

		case HCI_SCODATA_PKT:
			if (len >= HCI_SCO_HDR_SIZE) {
				struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) buf;
				pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
			} else {
				bt_dev_err(data->hdev, "audio block is too short");
				return -EILSEQ;
			}
			break;
		}

		skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
		if (!skb) {
			bt_dev_err(data->hdev, "no memory for the packet");
			return -ENOMEM;
		}

		hci_skb_pkt_type(skb) = pkt_type;

		data->reassembly = skb;
	} else {
		if (!data->reassembly) {
			bt_dev_err(data->hdev, "unexpected continuation block");
			return -EIO;
		}
	}

	if (len > 0)
		skb_put_data(data->reassembly, buf, len);

	if (hdr & 0x08) {
		hci_recv_frame(data->hdev, data->reassembly);
		data->reassembly = NULL;
	}

	return 0;
}