162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Bluetooth HCI UART driver 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000-2001 Qualcomm Incorporated 762306a36Sopenharmony_ci * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> 862306a36Sopenharmony_ci * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/types.h> 1662306a36Sopenharmony_ci#include <linux/fcntl.h> 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/ptrace.h> 1962306a36Sopenharmony_ci#include <linux/poll.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/tty.h> 2362306a36Sopenharmony_ci#include <linux/errno.h> 2462306a36Sopenharmony_ci#include <linux/string.h> 2562306a36Sopenharmony_ci#include <linux/signal.h> 2662306a36Sopenharmony_ci#include <linux/ioctl.h> 2762306a36Sopenharmony_ci#include <linux/skbuff.h> 2862306a36Sopenharmony_ci#include <asm/unaligned.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 3162306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "hci_uart.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistruct h4_struct { 3662306a36Sopenharmony_ci struct sk_buff *rx_skb; 3762306a36Sopenharmony_ci struct sk_buff_head txq; 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* Initialize protocol */ 4162306a36Sopenharmony_cistatic int h4_open(struct hci_uart *hu) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct h4_struct *h4; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci BT_DBG("hu %p", hu); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci h4 = kzalloc(sizeof(*h4), GFP_KERNEL); 4862306a36Sopenharmony_ci if (!h4) 4962306a36Sopenharmony_ci return -ENOMEM; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci skb_queue_head_init(&h4->txq); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci hu->priv = h4; 5462306a36Sopenharmony_ci return 0; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* Flush protocol data */ 5862306a36Sopenharmony_cistatic int h4_flush(struct hci_uart *hu) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct h4_struct *h4 = hu->priv; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci BT_DBG("hu %p", hu); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci skb_queue_purge(&h4->txq); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* Close protocol */ 7062306a36Sopenharmony_cistatic int h4_close(struct hci_uart *hu) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct h4_struct *h4 = hu->priv; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci BT_DBG("hu %p", hu); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci skb_queue_purge(&h4->txq); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci kfree_skb(h4->rx_skb); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci hu->priv = NULL; 8162306a36Sopenharmony_ci kfree(h4); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* Enqueue frame for transmission (padding, crc, etc) */ 8762306a36Sopenharmony_cistatic int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct h4_struct *h4 = hu->priv; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci BT_DBG("hu %p skb %p", hu, skb); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* Prepend skb with frame type */ 9462306a36Sopenharmony_ci memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); 9562306a36Sopenharmony_ci skb_queue_tail(&h4->txq, skb); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic const struct h4_recv_pkt h4_recv_pkts[] = { 10162306a36Sopenharmony_ci { H4_RECV_ACL, .recv = hci_recv_frame }, 10262306a36Sopenharmony_ci { H4_RECV_SCO, .recv = hci_recv_frame }, 10362306a36Sopenharmony_ci { H4_RECV_EVENT, .recv = hci_recv_frame }, 10462306a36Sopenharmony_ci { H4_RECV_ISO, .recv = hci_recv_frame }, 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* Recv data */ 10862306a36Sopenharmony_cistatic int h4_recv(struct hci_uart *hu, const void *data, int count) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct h4_struct *h4 = hu->priv; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) 11362306a36Sopenharmony_ci return -EUNATCH; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci h4->rx_skb = h4_recv_buf(hu->hdev, h4->rx_skb, data, count, 11662306a36Sopenharmony_ci h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts)); 11762306a36Sopenharmony_ci if (IS_ERR(h4->rx_skb)) { 11862306a36Sopenharmony_ci int err = PTR_ERR(h4->rx_skb); 11962306a36Sopenharmony_ci bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err); 12062306a36Sopenharmony_ci h4->rx_skb = NULL; 12162306a36Sopenharmony_ci return err; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return count; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic struct sk_buff *h4_dequeue(struct hci_uart *hu) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct h4_struct *h4 = hu->priv; 13062306a36Sopenharmony_ci return skb_dequeue(&h4->txq); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic const struct hci_uart_proto h4p = { 13462306a36Sopenharmony_ci .id = HCI_UART_H4, 13562306a36Sopenharmony_ci .name = "H4", 13662306a36Sopenharmony_ci .open = h4_open, 13762306a36Sopenharmony_ci .close = h4_close, 13862306a36Sopenharmony_ci .recv = h4_recv, 13962306a36Sopenharmony_ci .enqueue = h4_enqueue, 14062306a36Sopenharmony_ci .dequeue = h4_dequeue, 14162306a36Sopenharmony_ci .flush = h4_flush, 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ciint __init h4_init(void) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci return hci_uart_register_proto(&h4p); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ciint __exit h4_deinit(void) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci return hci_uart_unregister_proto(&h4p); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistruct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, 15562306a36Sopenharmony_ci const unsigned char *buffer, int count, 15662306a36Sopenharmony_ci const struct h4_recv_pkt *pkts, int pkts_count) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct hci_uart *hu = hci_get_drvdata(hdev); 15962306a36Sopenharmony_ci u8 alignment = hu->alignment ? hu->alignment : 1; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Check for error from previous call */ 16262306a36Sopenharmony_ci if (IS_ERR(skb)) 16362306a36Sopenharmony_ci skb = NULL; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci while (count) { 16662306a36Sopenharmony_ci int i, len; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* remove padding bytes from buffer */ 16962306a36Sopenharmony_ci for (; hu->padding && count > 0; hu->padding--) { 17062306a36Sopenharmony_ci count--; 17162306a36Sopenharmony_ci buffer++; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci if (!count) 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (!skb) { 17762306a36Sopenharmony_ci for (i = 0; i < pkts_count; i++) { 17862306a36Sopenharmony_ci if (buffer[0] != (&pkts[i])->type) 17962306a36Sopenharmony_ci continue; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci skb = bt_skb_alloc((&pkts[i])->maxlen, 18262306a36Sopenharmony_ci GFP_ATOMIC); 18362306a36Sopenharmony_ci if (!skb) 18462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci hci_skb_pkt_type(skb) = (&pkts[i])->type; 18762306a36Sopenharmony_ci hci_skb_expect(skb) = (&pkts[i])->hlen; 18862306a36Sopenharmony_ci break; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* Check for invalid packet type */ 19262306a36Sopenharmony_ci if (!skb) 19362306a36Sopenharmony_ci return ERR_PTR(-EILSEQ); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci count -= 1; 19662306a36Sopenharmony_ci buffer += 1; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci len = min_t(uint, hci_skb_expect(skb) - skb->len, count); 20062306a36Sopenharmony_ci skb_put_data(skb, buffer, len); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci count -= len; 20362306a36Sopenharmony_ci buffer += len; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Check for partial packet */ 20662306a36Sopenharmony_ci if (skb->len < hci_skb_expect(skb)) 20762306a36Sopenharmony_ci continue; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci for (i = 0; i < pkts_count; i++) { 21062306a36Sopenharmony_ci if (hci_skb_pkt_type(skb) == (&pkts[i])->type) 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (i >= pkts_count) { 21562306a36Sopenharmony_ci kfree_skb(skb); 21662306a36Sopenharmony_ci return ERR_PTR(-EILSEQ); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (skb->len == (&pkts[i])->hlen) { 22062306a36Sopenharmony_ci u16 dlen; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci switch ((&pkts[i])->lsize) { 22362306a36Sopenharmony_ci case 0: 22462306a36Sopenharmony_ci /* No variable data length */ 22562306a36Sopenharmony_ci dlen = 0; 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci case 1: 22862306a36Sopenharmony_ci /* Single octet variable length */ 22962306a36Sopenharmony_ci dlen = skb->data[(&pkts[i])->loff]; 23062306a36Sopenharmony_ci hci_skb_expect(skb) += dlen; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (skb_tailroom(skb) < dlen) { 23362306a36Sopenharmony_ci kfree_skb(skb); 23462306a36Sopenharmony_ci return ERR_PTR(-EMSGSIZE); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci case 2: 23862306a36Sopenharmony_ci /* Double octet variable length */ 23962306a36Sopenharmony_ci dlen = get_unaligned_le16(skb->data + 24062306a36Sopenharmony_ci (&pkts[i])->loff); 24162306a36Sopenharmony_ci hci_skb_expect(skb) += dlen; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (skb_tailroom(skb) < dlen) { 24462306a36Sopenharmony_ci kfree_skb(skb); 24562306a36Sopenharmony_ci return ERR_PTR(-EMSGSIZE); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci default: 24962306a36Sopenharmony_ci /* Unsupported variable length */ 25062306a36Sopenharmony_ci kfree_skb(skb); 25162306a36Sopenharmony_ci return ERR_PTR(-EILSEQ); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (!dlen) { 25562306a36Sopenharmony_ci hu->padding = (skb->len + 1) % alignment; 25662306a36Sopenharmony_ci hu->padding = (alignment - hu->padding) % alignment; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* No more data, complete frame */ 25962306a36Sopenharmony_ci (&pkts[i])->recv(hdev, skb); 26062306a36Sopenharmony_ci skb = NULL; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci } else { 26362306a36Sopenharmony_ci hu->padding = (skb->len + 1) % alignment; 26462306a36Sopenharmony_ci hu->padding = (alignment - hu->padding) % alignment; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* Complete frame */ 26762306a36Sopenharmony_ci (&pkts[i])->recv(hdev, skb); 26862306a36Sopenharmony_ci skb = NULL; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return skb; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(h4_recv_buf); 275