18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci BlueZ - Bluetooth protocol stack for Linux 38c2ecf20Sopenharmony_ci Copyright (C) 2000-2001 Qualcomm Incorporated 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci This program is free software; you can redistribute it and/or modify 88c2ecf20Sopenharmony_ci it under the terms of the GNU General Public License version 2 as 98c2ecf20Sopenharmony_ci published by the Free Software Foundation; 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 128c2ecf20Sopenharmony_ci OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 138c2ecf20Sopenharmony_ci FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 148c2ecf20Sopenharmony_ci IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 158c2ecf20Sopenharmony_ci CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 168c2ecf20Sopenharmony_ci WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 178c2ecf20Sopenharmony_ci ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 188c2ecf20Sopenharmony_ci OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 218c2ecf20Sopenharmony_ci COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 228c2ecf20Sopenharmony_ci SOFTWARE IS DISCLAIMED. 238c2ecf20Sopenharmony_ci*/ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Bluetooth HCI sockets. */ 268c2ecf20Sopenharmony_ci#include <linux/compat.h> 278c2ecf20Sopenharmony_ci#include <linux/export.h> 288c2ecf20Sopenharmony_ci#include <linux/utsname.h> 298c2ecf20Sopenharmony_ci#include <linux/sched.h> 308c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 338c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h> 348c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_mon.h> 358c2ecf20Sopenharmony_ci#include <net/bluetooth/mgmt.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "mgmt_util.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic LIST_HEAD(mgmt_chan_list); 408c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(mgmt_chan_list_lock); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic DEFINE_IDA(sock_cookie_ida); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic atomic_t monitor_promisc = ATOMIC_INIT(0); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* ----- HCI socket interface ----- */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Socket info */ 498c2ecf20Sopenharmony_ci#define hci_pi(sk) ((struct hci_pinfo *) sk) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct hci_pinfo { 528c2ecf20Sopenharmony_ci struct bt_sock bt; 538c2ecf20Sopenharmony_ci struct hci_dev *hdev; 548c2ecf20Sopenharmony_ci struct hci_filter filter; 558c2ecf20Sopenharmony_ci __u8 cmsg_mask; 568c2ecf20Sopenharmony_ci unsigned short channel; 578c2ecf20Sopenharmony_ci unsigned long flags; 588c2ecf20Sopenharmony_ci __u32 cookie; 598c2ecf20Sopenharmony_ci char comm[TASK_COMM_LEN]; 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic struct hci_dev *hci_hdev_from_sock(struct sock *sk) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct hci_dev *hdev = hci_pi(sk)->hdev; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (!hdev) 678c2ecf20Sopenharmony_ci return ERR_PTR(-EBADFD); 688c2ecf20Sopenharmony_ci if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) 698c2ecf20Sopenharmony_ci return ERR_PTR(-EPIPE); 708c2ecf20Sopenharmony_ci return hdev; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_civoid hci_sock_set_flag(struct sock *sk, int nr) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci set_bit(nr, &hci_pi(sk)->flags); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_civoid hci_sock_clear_flag(struct sock *sk, int nr) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci clear_bit(nr, &hci_pi(sk)->flags); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciint hci_sock_test_flag(struct sock *sk, int nr) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci return test_bit(nr, &hci_pi(sk)->flags); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ciunsigned short hci_sock_get_channel(struct sock *sk) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci return hci_pi(sk)->channel; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciu32 hci_sock_get_cookie(struct sock *sk) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci return hci_pi(sk)->cookie; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic bool hci_sock_gen_cookie(struct sock *sk) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci int id = hci_pi(sk)->cookie; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (!id) { 1038c2ecf20Sopenharmony_ci id = ida_simple_get(&sock_cookie_ida, 1, 0, GFP_KERNEL); 1048c2ecf20Sopenharmony_ci if (id < 0) 1058c2ecf20Sopenharmony_ci id = 0xffffffff; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci hci_pi(sk)->cookie = id; 1088c2ecf20Sopenharmony_ci get_task_comm(hci_pi(sk)->comm, current); 1098c2ecf20Sopenharmony_ci return true; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return false; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void hci_sock_free_cookie(struct sock *sk) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci int id = hci_pi(sk)->cookie; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (id) { 1208c2ecf20Sopenharmony_ci hci_pi(sk)->cookie = 0xffffffff; 1218c2ecf20Sopenharmony_ci ida_simple_remove(&sock_cookie_ida, id); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic inline int hci_test_bit(int nr, const void *addr) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci return *((const __u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31)); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* Security filter */ 1318c2ecf20Sopenharmony_ci#define HCI_SFLT_MAX_OGF 5 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistruct hci_sec_filter { 1348c2ecf20Sopenharmony_ci __u32 type_mask; 1358c2ecf20Sopenharmony_ci __u32 event_mask[2]; 1368c2ecf20Sopenharmony_ci __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic const struct hci_sec_filter hci_sec_filter = { 1408c2ecf20Sopenharmony_ci /* Packet types */ 1418c2ecf20Sopenharmony_ci 0x10, 1428c2ecf20Sopenharmony_ci /* Events */ 1438c2ecf20Sopenharmony_ci { 0x1000d9fe, 0x0000b00c }, 1448c2ecf20Sopenharmony_ci /* Commands */ 1458c2ecf20Sopenharmony_ci { 1468c2ecf20Sopenharmony_ci { 0x0 }, 1478c2ecf20Sopenharmony_ci /* OGF_LINK_CTL */ 1488c2ecf20Sopenharmony_ci { 0xbe000006, 0x00000001, 0x00000000, 0x00 }, 1498c2ecf20Sopenharmony_ci /* OGF_LINK_POLICY */ 1508c2ecf20Sopenharmony_ci { 0x00005200, 0x00000000, 0x00000000, 0x00 }, 1518c2ecf20Sopenharmony_ci /* OGF_HOST_CTL */ 1528c2ecf20Sopenharmony_ci { 0xaab00200, 0x2b402aaa, 0x05220154, 0x00 }, 1538c2ecf20Sopenharmony_ci /* OGF_INFO_PARAM */ 1548c2ecf20Sopenharmony_ci { 0x000002be, 0x00000000, 0x00000000, 0x00 }, 1558c2ecf20Sopenharmony_ci /* OGF_STATUS_PARAM */ 1568c2ecf20Sopenharmony_ci { 0x000000ea, 0x00000000, 0x00000000, 0x00 } 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic struct bt_sock_list hci_sk_list = { 1618c2ecf20Sopenharmony_ci .lock = __RW_LOCK_UNLOCKED(hci_sk_list.lock) 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic bool is_filtered_packet(struct sock *sk, struct sk_buff *skb) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct hci_filter *flt; 1678c2ecf20Sopenharmony_ci int flt_type, flt_event; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* Apply filter */ 1708c2ecf20Sopenharmony_ci flt = &hci_pi(sk)->filter; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci flt_type = hci_skb_pkt_type(skb) & HCI_FLT_TYPE_BITS; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!test_bit(flt_type, &flt->type_mask)) 1758c2ecf20Sopenharmony_ci return true; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* Extra filter for event packets only */ 1788c2ecf20Sopenharmony_ci if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT) 1798c2ecf20Sopenharmony_ci return false; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci flt_event = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (!hci_test_bit(flt_event, &flt->event_mask)) 1848c2ecf20Sopenharmony_ci return true; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Check filter only when opcode is set */ 1878c2ecf20Sopenharmony_ci if (!flt->opcode) 1888c2ecf20Sopenharmony_ci return false; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (flt_event == HCI_EV_CMD_COMPLETE && 1918c2ecf20Sopenharmony_ci flt->opcode != get_unaligned((__le16 *)(skb->data + 3))) 1928c2ecf20Sopenharmony_ci return true; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (flt_event == HCI_EV_CMD_STATUS && 1958c2ecf20Sopenharmony_ci flt->opcode != get_unaligned((__le16 *)(skb->data + 4))) 1968c2ecf20Sopenharmony_ci return true; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return false; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* Send frame to RAW socket */ 2028c2ecf20Sopenharmony_civoid hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct sock *sk; 2058c2ecf20Sopenharmony_ci struct sk_buff *skb_copy = NULL; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci BT_DBG("hdev %p len %d", hdev, skb->len); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci read_lock(&hci_sk_list.lock); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci sk_for_each(sk, &hci_sk_list.head) { 2128c2ecf20Sopenharmony_ci struct sk_buff *nskb; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev) 2158c2ecf20Sopenharmony_ci continue; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* Don't send frame to the socket it came from */ 2188c2ecf20Sopenharmony_ci if (skb->sk == sk) 2198c2ecf20Sopenharmony_ci continue; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (hci_pi(sk)->channel == HCI_CHANNEL_RAW) { 2228c2ecf20Sopenharmony_ci if (hci_skb_pkt_type(skb) != HCI_COMMAND_PKT && 2238c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_EVENT_PKT && 2248c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT && 2258c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_SCODATA_PKT && 2268c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_ISODATA_PKT) 2278c2ecf20Sopenharmony_ci continue; 2288c2ecf20Sopenharmony_ci if (is_filtered_packet(sk, skb)) 2298c2ecf20Sopenharmony_ci continue; 2308c2ecf20Sopenharmony_ci } else if (hci_pi(sk)->channel == HCI_CHANNEL_USER) { 2318c2ecf20Sopenharmony_ci if (!bt_cb(skb)->incoming) 2328c2ecf20Sopenharmony_ci continue; 2338c2ecf20Sopenharmony_ci if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT && 2348c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT && 2358c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_SCODATA_PKT && 2368c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_ISODATA_PKT) 2378c2ecf20Sopenharmony_ci continue; 2388c2ecf20Sopenharmony_ci } else { 2398c2ecf20Sopenharmony_ci /* Don't send frame to other channel types */ 2408c2ecf20Sopenharmony_ci continue; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (!skb_copy) { 2448c2ecf20Sopenharmony_ci /* Create a private copy with headroom */ 2458c2ecf20Sopenharmony_ci skb_copy = __pskb_copy_fclone(skb, 1, GFP_ATOMIC, true); 2468c2ecf20Sopenharmony_ci if (!skb_copy) 2478c2ecf20Sopenharmony_ci continue; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* Put type byte before the data */ 2508c2ecf20Sopenharmony_ci memcpy(skb_push(skb_copy, 1), &hci_skb_pkt_type(skb), 1); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci nskb = skb_clone(skb_copy, GFP_ATOMIC); 2548c2ecf20Sopenharmony_ci if (!nskb) 2558c2ecf20Sopenharmony_ci continue; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (sock_queue_rcv_skb(sk, nskb)) 2588c2ecf20Sopenharmony_ci kfree_skb(nskb); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci read_unlock(&hci_sk_list.lock); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci kfree_skb(skb_copy); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* Send frame to sockets with specific channel */ 2678c2ecf20Sopenharmony_cistatic void __hci_send_to_channel(unsigned short channel, struct sk_buff *skb, 2688c2ecf20Sopenharmony_ci int flag, struct sock *skip_sk) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct sock *sk; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci BT_DBG("channel %u len %d", channel, skb->len); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci sk_for_each(sk, &hci_sk_list.head) { 2758c2ecf20Sopenharmony_ci struct sk_buff *nskb; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* Ignore socket without the flag set */ 2788c2ecf20Sopenharmony_ci if (!hci_sock_test_flag(sk, flag)) 2798c2ecf20Sopenharmony_ci continue; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Skip the original socket */ 2828c2ecf20Sopenharmony_ci if (sk == skip_sk) 2838c2ecf20Sopenharmony_ci continue; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (sk->sk_state != BT_BOUND) 2868c2ecf20Sopenharmony_ci continue; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (hci_pi(sk)->channel != channel) 2898c2ecf20Sopenharmony_ci continue; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci nskb = skb_clone(skb, GFP_ATOMIC); 2928c2ecf20Sopenharmony_ci if (!nskb) 2938c2ecf20Sopenharmony_ci continue; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (sock_queue_rcv_skb(sk, nskb)) 2968c2ecf20Sopenharmony_ci kfree_skb(nskb); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_civoid hci_send_to_channel(unsigned short channel, struct sk_buff *skb, 3028c2ecf20Sopenharmony_ci int flag, struct sock *skip_sk) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci read_lock(&hci_sk_list.lock); 3058c2ecf20Sopenharmony_ci __hci_send_to_channel(channel, skb, flag, skip_sk); 3068c2ecf20Sopenharmony_ci read_unlock(&hci_sk_list.lock); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* Send frame to monitor socket */ 3108c2ecf20Sopenharmony_civoid hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct sk_buff *skb_copy = NULL; 3138c2ecf20Sopenharmony_ci struct hci_mon_hdr *hdr; 3148c2ecf20Sopenharmony_ci __le16 opcode; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!atomic_read(&monitor_promisc)) 3178c2ecf20Sopenharmony_ci return; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci BT_DBG("hdev %p len %d", hdev, skb->len); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci switch (hci_skb_pkt_type(skb)) { 3228c2ecf20Sopenharmony_ci case HCI_COMMAND_PKT: 3238c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_COMMAND_PKT); 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci case HCI_EVENT_PKT: 3268c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_EVENT_PKT); 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci case HCI_ACLDATA_PKT: 3298c2ecf20Sopenharmony_ci if (bt_cb(skb)->incoming) 3308c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_ACL_RX_PKT); 3318c2ecf20Sopenharmony_ci else 3328c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_ACL_TX_PKT); 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci case HCI_SCODATA_PKT: 3358c2ecf20Sopenharmony_ci if (bt_cb(skb)->incoming) 3368c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_SCO_RX_PKT); 3378c2ecf20Sopenharmony_ci else 3388c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_SCO_TX_PKT); 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci case HCI_ISODATA_PKT: 3418c2ecf20Sopenharmony_ci if (bt_cb(skb)->incoming) 3428c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_ISO_RX_PKT); 3438c2ecf20Sopenharmony_ci else 3448c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_ISO_TX_PKT); 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci case HCI_DIAG_PKT: 3478c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_VENDOR_DIAG); 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci default: 3508c2ecf20Sopenharmony_ci return; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* Create a private copy with headroom */ 3548c2ecf20Sopenharmony_ci skb_copy = __pskb_copy_fclone(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC, true); 3558c2ecf20Sopenharmony_ci if (!skb_copy) 3568c2ecf20Sopenharmony_ci return; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Put header before the data */ 3598c2ecf20Sopenharmony_ci hdr = skb_push(skb_copy, HCI_MON_HDR_SIZE); 3608c2ecf20Sopenharmony_ci hdr->opcode = opcode; 3618c2ecf20Sopenharmony_ci hdr->index = cpu_to_le16(hdev->id); 3628c2ecf20Sopenharmony_ci hdr->len = cpu_to_le16(skb->len); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb_copy, 3658c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 3668c2ecf20Sopenharmony_ci kfree_skb(skb_copy); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_civoid hci_send_monitor_ctrl_event(struct hci_dev *hdev, u16 event, 3708c2ecf20Sopenharmony_ci void *data, u16 data_len, ktime_t tstamp, 3718c2ecf20Sopenharmony_ci int flag, struct sock *skip_sk) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct sock *sk; 3748c2ecf20Sopenharmony_ci __le16 index; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (hdev) 3778c2ecf20Sopenharmony_ci index = cpu_to_le16(hdev->id); 3788c2ecf20Sopenharmony_ci else 3798c2ecf20Sopenharmony_ci index = cpu_to_le16(MGMT_INDEX_NONE); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci read_lock(&hci_sk_list.lock); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci sk_for_each(sk, &hci_sk_list.head) { 3848c2ecf20Sopenharmony_ci struct hci_mon_hdr *hdr; 3858c2ecf20Sopenharmony_ci struct sk_buff *skb; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (hci_pi(sk)->channel != HCI_CHANNEL_CONTROL) 3888c2ecf20Sopenharmony_ci continue; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* Ignore socket without the flag set */ 3918c2ecf20Sopenharmony_ci if (!hci_sock_test_flag(sk, flag)) 3928c2ecf20Sopenharmony_ci continue; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* Skip the original socket */ 3958c2ecf20Sopenharmony_ci if (sk == skip_sk) 3968c2ecf20Sopenharmony_ci continue; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci skb = bt_skb_alloc(6 + data_len, GFP_ATOMIC); 3998c2ecf20Sopenharmony_ci if (!skb) 4008c2ecf20Sopenharmony_ci continue; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4)); 4038c2ecf20Sopenharmony_ci put_unaligned_le16(event, skb_put(skb, 2)); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (data) 4068c2ecf20Sopenharmony_ci skb_put_data(skb, data, data_len); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci skb->tstamp = tstamp; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci hdr = skb_push(skb, HCI_MON_HDR_SIZE); 4118c2ecf20Sopenharmony_ci hdr->opcode = cpu_to_le16(HCI_MON_CTRL_EVENT); 4128c2ecf20Sopenharmony_ci hdr->index = index; 4138c2ecf20Sopenharmony_ci hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci __hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 4168c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 4178c2ecf20Sopenharmony_ci kfree_skb(skb); 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci read_unlock(&hci_sk_list.lock); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct hci_mon_hdr *hdr; 4268c2ecf20Sopenharmony_ci struct hci_mon_new_index *ni; 4278c2ecf20Sopenharmony_ci struct hci_mon_index_info *ii; 4288c2ecf20Sopenharmony_ci struct sk_buff *skb; 4298c2ecf20Sopenharmony_ci __le16 opcode; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci switch (event) { 4328c2ecf20Sopenharmony_ci case HCI_DEV_REG: 4338c2ecf20Sopenharmony_ci skb = bt_skb_alloc(HCI_MON_NEW_INDEX_SIZE, GFP_ATOMIC); 4348c2ecf20Sopenharmony_ci if (!skb) 4358c2ecf20Sopenharmony_ci return NULL; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci ni = skb_put(skb, HCI_MON_NEW_INDEX_SIZE); 4388c2ecf20Sopenharmony_ci ni->type = hdev->dev_type; 4398c2ecf20Sopenharmony_ci ni->bus = hdev->bus; 4408c2ecf20Sopenharmony_ci bacpy(&ni->bdaddr, &hdev->bdaddr); 4418c2ecf20Sopenharmony_ci memcpy_and_pad(ni->name, sizeof(ni->name), hdev->name, 4428c2ecf20Sopenharmony_ci strnlen(hdev->name, sizeof(ni->name)), '\0'); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_NEW_INDEX); 4458c2ecf20Sopenharmony_ci break; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci case HCI_DEV_UNREG: 4488c2ecf20Sopenharmony_ci skb = bt_skb_alloc(0, GFP_ATOMIC); 4498c2ecf20Sopenharmony_ci if (!skb) 4508c2ecf20Sopenharmony_ci return NULL; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_DEL_INDEX); 4538c2ecf20Sopenharmony_ci break; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci case HCI_DEV_SETUP: 4568c2ecf20Sopenharmony_ci if (hdev->manufacturer == 0xffff) 4578c2ecf20Sopenharmony_ci return NULL; 4588c2ecf20Sopenharmony_ci fallthrough; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci case HCI_DEV_UP: 4618c2ecf20Sopenharmony_ci skb = bt_skb_alloc(HCI_MON_INDEX_INFO_SIZE, GFP_ATOMIC); 4628c2ecf20Sopenharmony_ci if (!skb) 4638c2ecf20Sopenharmony_ci return NULL; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci ii = skb_put(skb, HCI_MON_INDEX_INFO_SIZE); 4668c2ecf20Sopenharmony_ci bacpy(&ii->bdaddr, &hdev->bdaddr); 4678c2ecf20Sopenharmony_ci ii->manufacturer = cpu_to_le16(hdev->manufacturer); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_INDEX_INFO); 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci case HCI_DEV_OPEN: 4738c2ecf20Sopenharmony_ci skb = bt_skb_alloc(0, GFP_ATOMIC); 4748c2ecf20Sopenharmony_ci if (!skb) 4758c2ecf20Sopenharmony_ci return NULL; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_OPEN_INDEX); 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci case HCI_DEV_CLOSE: 4818c2ecf20Sopenharmony_ci skb = bt_skb_alloc(0, GFP_ATOMIC); 4828c2ecf20Sopenharmony_ci if (!skb) 4838c2ecf20Sopenharmony_ci return NULL; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci opcode = cpu_to_le16(HCI_MON_CLOSE_INDEX); 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci default: 4898c2ecf20Sopenharmony_ci return NULL; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci __net_timestamp(skb); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci hdr = skb_push(skb, HCI_MON_HDR_SIZE); 4958c2ecf20Sopenharmony_ci hdr->opcode = opcode; 4968c2ecf20Sopenharmony_ci hdr->index = cpu_to_le16(hdev->id); 4978c2ecf20Sopenharmony_ci hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci return skb; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic struct sk_buff *create_monitor_ctrl_open(struct sock *sk) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci struct hci_mon_hdr *hdr; 5058c2ecf20Sopenharmony_ci struct sk_buff *skb; 5068c2ecf20Sopenharmony_ci u16 format; 5078c2ecf20Sopenharmony_ci u8 ver[3]; 5088c2ecf20Sopenharmony_ci u32 flags; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* No message needed when cookie is not present */ 5118c2ecf20Sopenharmony_ci if (!hci_pi(sk)->cookie) 5128c2ecf20Sopenharmony_ci return NULL; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci switch (hci_pi(sk)->channel) { 5158c2ecf20Sopenharmony_ci case HCI_CHANNEL_RAW: 5168c2ecf20Sopenharmony_ci format = 0x0000; 5178c2ecf20Sopenharmony_ci ver[0] = BT_SUBSYS_VERSION; 5188c2ecf20Sopenharmony_ci put_unaligned_le16(BT_SUBSYS_REVISION, ver + 1); 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci case HCI_CHANNEL_USER: 5218c2ecf20Sopenharmony_ci format = 0x0001; 5228c2ecf20Sopenharmony_ci ver[0] = BT_SUBSYS_VERSION; 5238c2ecf20Sopenharmony_ci put_unaligned_le16(BT_SUBSYS_REVISION, ver + 1); 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci case HCI_CHANNEL_CONTROL: 5268c2ecf20Sopenharmony_ci format = 0x0002; 5278c2ecf20Sopenharmony_ci mgmt_fill_version_info(ver); 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci default: 5308c2ecf20Sopenharmony_ci /* No message for unsupported format */ 5318c2ecf20Sopenharmony_ci return NULL; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci skb = bt_skb_alloc(14 + TASK_COMM_LEN , GFP_ATOMIC); 5358c2ecf20Sopenharmony_ci if (!skb) 5368c2ecf20Sopenharmony_ci return NULL; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci flags = hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) ? 0x1 : 0x0; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4)); 5418c2ecf20Sopenharmony_ci put_unaligned_le16(format, skb_put(skb, 2)); 5428c2ecf20Sopenharmony_ci skb_put_data(skb, ver, sizeof(ver)); 5438c2ecf20Sopenharmony_ci put_unaligned_le32(flags, skb_put(skb, 4)); 5448c2ecf20Sopenharmony_ci skb_put_u8(skb, TASK_COMM_LEN); 5458c2ecf20Sopenharmony_ci skb_put_data(skb, hci_pi(sk)->comm, TASK_COMM_LEN); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci __net_timestamp(skb); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci hdr = skb_push(skb, HCI_MON_HDR_SIZE); 5508c2ecf20Sopenharmony_ci hdr->opcode = cpu_to_le16(HCI_MON_CTRL_OPEN); 5518c2ecf20Sopenharmony_ci if (hci_pi(sk)->hdev) 5528c2ecf20Sopenharmony_ci hdr->index = cpu_to_le16(hci_pi(sk)->hdev->id); 5538c2ecf20Sopenharmony_ci else 5548c2ecf20Sopenharmony_ci hdr->index = cpu_to_le16(HCI_DEV_NONE); 5558c2ecf20Sopenharmony_ci hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return skb; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic struct sk_buff *create_monitor_ctrl_close(struct sock *sk) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct hci_mon_hdr *hdr; 5638c2ecf20Sopenharmony_ci struct sk_buff *skb; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* No message needed when cookie is not present */ 5668c2ecf20Sopenharmony_ci if (!hci_pi(sk)->cookie) 5678c2ecf20Sopenharmony_ci return NULL; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci switch (hci_pi(sk)->channel) { 5708c2ecf20Sopenharmony_ci case HCI_CHANNEL_RAW: 5718c2ecf20Sopenharmony_ci case HCI_CHANNEL_USER: 5728c2ecf20Sopenharmony_ci case HCI_CHANNEL_CONTROL: 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci default: 5758c2ecf20Sopenharmony_ci /* No message for unsupported format */ 5768c2ecf20Sopenharmony_ci return NULL; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci skb = bt_skb_alloc(4, GFP_ATOMIC); 5808c2ecf20Sopenharmony_ci if (!skb) 5818c2ecf20Sopenharmony_ci return NULL; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4)); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci __net_timestamp(skb); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci hdr = skb_push(skb, HCI_MON_HDR_SIZE); 5888c2ecf20Sopenharmony_ci hdr->opcode = cpu_to_le16(HCI_MON_CTRL_CLOSE); 5898c2ecf20Sopenharmony_ci if (hci_pi(sk)->hdev) 5908c2ecf20Sopenharmony_ci hdr->index = cpu_to_le16(hci_pi(sk)->hdev->id); 5918c2ecf20Sopenharmony_ci else 5928c2ecf20Sopenharmony_ci hdr->index = cpu_to_le16(HCI_DEV_NONE); 5938c2ecf20Sopenharmony_ci hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci return skb; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic struct sk_buff *create_monitor_ctrl_command(struct sock *sk, u16 index, 5998c2ecf20Sopenharmony_ci u16 opcode, u16 len, 6008c2ecf20Sopenharmony_ci const void *buf) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci struct hci_mon_hdr *hdr; 6038c2ecf20Sopenharmony_ci struct sk_buff *skb; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci skb = bt_skb_alloc(6 + len, GFP_ATOMIC); 6068c2ecf20Sopenharmony_ci if (!skb) 6078c2ecf20Sopenharmony_ci return NULL; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci put_unaligned_le32(hci_pi(sk)->cookie, skb_put(skb, 4)); 6108c2ecf20Sopenharmony_ci put_unaligned_le16(opcode, skb_put(skb, 2)); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (buf) 6138c2ecf20Sopenharmony_ci skb_put_data(skb, buf, len); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci __net_timestamp(skb); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci hdr = skb_push(skb, HCI_MON_HDR_SIZE); 6188c2ecf20Sopenharmony_ci hdr->opcode = cpu_to_le16(HCI_MON_CTRL_COMMAND); 6198c2ecf20Sopenharmony_ci hdr->index = cpu_to_le16(index); 6208c2ecf20Sopenharmony_ci hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return skb; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic void __printf(2, 3) 6268c2ecf20Sopenharmony_cisend_monitor_note(struct sock *sk, const char *fmt, ...) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci size_t len; 6298c2ecf20Sopenharmony_ci struct hci_mon_hdr *hdr; 6308c2ecf20Sopenharmony_ci struct sk_buff *skb; 6318c2ecf20Sopenharmony_ci va_list args; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci va_start(args, fmt); 6348c2ecf20Sopenharmony_ci len = vsnprintf(NULL, 0, fmt, args); 6358c2ecf20Sopenharmony_ci va_end(args); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci skb = bt_skb_alloc(len + 1, GFP_ATOMIC); 6388c2ecf20Sopenharmony_ci if (!skb) 6398c2ecf20Sopenharmony_ci return; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci va_start(args, fmt); 6428c2ecf20Sopenharmony_ci vsprintf(skb_put(skb, len), fmt, args); 6438c2ecf20Sopenharmony_ci *(u8 *)skb_put(skb, 1) = 0; 6448c2ecf20Sopenharmony_ci va_end(args); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci __net_timestamp(skb); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci hdr = (void *)skb_push(skb, HCI_MON_HDR_SIZE); 6498c2ecf20Sopenharmony_ci hdr->opcode = cpu_to_le16(HCI_MON_SYSTEM_NOTE); 6508c2ecf20Sopenharmony_ci hdr->index = cpu_to_le16(HCI_DEV_NONE); 6518c2ecf20Sopenharmony_ci hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (sock_queue_rcv_skb(sk, skb)) 6548c2ecf20Sopenharmony_ci kfree_skb(skb); 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic void send_monitor_replay(struct sock *sk) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct hci_dev *hdev; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci read_lock(&hci_dev_list_lock); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci list_for_each_entry(hdev, &hci_dev_list, list) { 6648c2ecf20Sopenharmony_ci struct sk_buff *skb; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci skb = create_monitor_event(hdev, HCI_DEV_REG); 6678c2ecf20Sopenharmony_ci if (!skb) 6688c2ecf20Sopenharmony_ci continue; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (sock_queue_rcv_skb(sk, skb)) 6718c2ecf20Sopenharmony_ci kfree_skb(skb); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (!test_bit(HCI_RUNNING, &hdev->flags)) 6748c2ecf20Sopenharmony_ci continue; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci skb = create_monitor_event(hdev, HCI_DEV_OPEN); 6778c2ecf20Sopenharmony_ci if (!skb) 6788c2ecf20Sopenharmony_ci continue; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (sock_queue_rcv_skb(sk, skb)) 6818c2ecf20Sopenharmony_ci kfree_skb(skb); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (test_bit(HCI_UP, &hdev->flags)) 6848c2ecf20Sopenharmony_ci skb = create_monitor_event(hdev, HCI_DEV_UP); 6858c2ecf20Sopenharmony_ci else if (hci_dev_test_flag(hdev, HCI_SETUP)) 6868c2ecf20Sopenharmony_ci skb = create_monitor_event(hdev, HCI_DEV_SETUP); 6878c2ecf20Sopenharmony_ci else 6888c2ecf20Sopenharmony_ci skb = NULL; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (skb) { 6918c2ecf20Sopenharmony_ci if (sock_queue_rcv_skb(sk, skb)) 6928c2ecf20Sopenharmony_ci kfree_skb(skb); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci read_unlock(&hci_dev_list_lock); 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic void send_monitor_control_replay(struct sock *mon_sk) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct sock *sk; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci read_lock(&hci_sk_list.lock); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci sk_for_each(sk, &hci_sk_list.head) { 7068c2ecf20Sopenharmony_ci struct sk_buff *skb; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci skb = create_monitor_ctrl_open(sk); 7098c2ecf20Sopenharmony_ci if (!skb) 7108c2ecf20Sopenharmony_ci continue; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (sock_queue_rcv_skb(mon_sk, skb)) 7138c2ecf20Sopenharmony_ci kfree_skb(skb); 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci read_unlock(&hci_sk_list.lock); 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci/* Generate internal stack event */ 7208c2ecf20Sopenharmony_cistatic void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct hci_event_hdr *hdr; 7238c2ecf20Sopenharmony_ci struct hci_ev_stack_internal *ev; 7248c2ecf20Sopenharmony_ci struct sk_buff *skb; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci skb = bt_skb_alloc(HCI_EVENT_HDR_SIZE + sizeof(*ev) + dlen, GFP_ATOMIC); 7278c2ecf20Sopenharmony_ci if (!skb) 7288c2ecf20Sopenharmony_ci return; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci hdr = skb_put(skb, HCI_EVENT_HDR_SIZE); 7318c2ecf20Sopenharmony_ci hdr->evt = HCI_EV_STACK_INTERNAL; 7328c2ecf20Sopenharmony_ci hdr->plen = sizeof(*ev) + dlen; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci ev = skb_put(skb, sizeof(*ev) + dlen); 7358c2ecf20Sopenharmony_ci ev->type = type; 7368c2ecf20Sopenharmony_ci memcpy(ev->data, data, dlen); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci bt_cb(skb)->incoming = 1; 7398c2ecf20Sopenharmony_ci __net_timestamp(skb); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) = HCI_EVENT_PKT; 7428c2ecf20Sopenharmony_ci hci_send_to_sock(hdev, skb); 7438c2ecf20Sopenharmony_ci kfree_skb(skb); 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_civoid hci_sock_dev_event(struct hci_dev *hdev, int event) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci BT_DBG("hdev %s event %d", hdev->name, event); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (atomic_read(&monitor_promisc)) { 7518c2ecf20Sopenharmony_ci struct sk_buff *skb; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* Send event to monitor */ 7548c2ecf20Sopenharmony_ci skb = create_monitor_event(hdev, event); 7558c2ecf20Sopenharmony_ci if (skb) { 7568c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 7578c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 7588c2ecf20Sopenharmony_ci kfree_skb(skb); 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (event <= HCI_DEV_DOWN) { 7638c2ecf20Sopenharmony_ci struct hci_ev_si_device ev; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* Send event to sockets */ 7668c2ecf20Sopenharmony_ci ev.event = event; 7678c2ecf20Sopenharmony_ci ev.dev_id = hdev->id; 7688c2ecf20Sopenharmony_ci hci_si_event(NULL, HCI_EV_SI_DEVICE, sizeof(ev), &ev); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (event == HCI_DEV_UNREG) { 7728c2ecf20Sopenharmony_ci struct sock *sk; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* Wake up sockets using this dead device */ 7758c2ecf20Sopenharmony_ci read_lock(&hci_sk_list.lock); 7768c2ecf20Sopenharmony_ci sk_for_each(sk, &hci_sk_list.head) { 7778c2ecf20Sopenharmony_ci if (hci_pi(sk)->hdev == hdev) { 7788c2ecf20Sopenharmony_ci sk->sk_err = EPIPE; 7798c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci read_unlock(&hci_sk_list.lock); 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic struct hci_mgmt_chan *__hci_mgmt_chan_find(unsigned short channel) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct hci_mgmt_chan *c; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci list_for_each_entry(c, &mgmt_chan_list, list) { 7918c2ecf20Sopenharmony_ci if (c->channel == channel) 7928c2ecf20Sopenharmony_ci return c; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci return NULL; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic struct hci_mgmt_chan *hci_mgmt_chan_find(unsigned short channel) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct hci_mgmt_chan *c; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci mutex_lock(&mgmt_chan_list_lock); 8038c2ecf20Sopenharmony_ci c = __hci_mgmt_chan_find(channel); 8048c2ecf20Sopenharmony_ci mutex_unlock(&mgmt_chan_list_lock); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci return c; 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ciint hci_mgmt_chan_register(struct hci_mgmt_chan *c) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci if (c->channel < HCI_CHANNEL_CONTROL) 8128c2ecf20Sopenharmony_ci return -EINVAL; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci mutex_lock(&mgmt_chan_list_lock); 8158c2ecf20Sopenharmony_ci if (__hci_mgmt_chan_find(c->channel)) { 8168c2ecf20Sopenharmony_ci mutex_unlock(&mgmt_chan_list_lock); 8178c2ecf20Sopenharmony_ci return -EALREADY; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci list_add_tail(&c->list, &mgmt_chan_list); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci mutex_unlock(&mgmt_chan_list_lock); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci return 0; 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hci_mgmt_chan_register); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_civoid hci_mgmt_chan_unregister(struct hci_mgmt_chan *c) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci mutex_lock(&mgmt_chan_list_lock); 8318c2ecf20Sopenharmony_ci list_del(&c->list); 8328c2ecf20Sopenharmony_ci mutex_unlock(&mgmt_chan_list_lock); 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hci_mgmt_chan_unregister); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic int hci_sock_release(struct socket *sock) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 8398c2ecf20Sopenharmony_ci struct hci_dev *hdev; 8408c2ecf20Sopenharmony_ci struct sk_buff *skb; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci BT_DBG("sock %p sk %p", sock, sk); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (!sk) 8458c2ecf20Sopenharmony_ci return 0; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci lock_sock(sk); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci switch (hci_pi(sk)->channel) { 8508c2ecf20Sopenharmony_ci case HCI_CHANNEL_MONITOR: 8518c2ecf20Sopenharmony_ci atomic_dec(&monitor_promisc); 8528c2ecf20Sopenharmony_ci break; 8538c2ecf20Sopenharmony_ci case HCI_CHANNEL_RAW: 8548c2ecf20Sopenharmony_ci case HCI_CHANNEL_USER: 8558c2ecf20Sopenharmony_ci case HCI_CHANNEL_CONTROL: 8568c2ecf20Sopenharmony_ci /* Send event to monitor */ 8578c2ecf20Sopenharmony_ci skb = create_monitor_ctrl_close(sk); 8588c2ecf20Sopenharmony_ci if (skb) { 8598c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 8608c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 8618c2ecf20Sopenharmony_ci kfree_skb(skb); 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci hci_sock_free_cookie(sk); 8658c2ecf20Sopenharmony_ci break; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci bt_sock_unlink(&hci_sk_list, sk); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci hdev = hci_pi(sk)->hdev; 8718c2ecf20Sopenharmony_ci if (hdev) { 8728c2ecf20Sopenharmony_ci if (hci_pi(sk)->channel == HCI_CHANNEL_USER) { 8738c2ecf20Sopenharmony_ci /* When releasing a user channel exclusive access, 8748c2ecf20Sopenharmony_ci * call hci_dev_do_close directly instead of calling 8758c2ecf20Sopenharmony_ci * hci_dev_close to ensure the exclusive access will 8768c2ecf20Sopenharmony_ci * be released and the controller brought back down. 8778c2ecf20Sopenharmony_ci * 8788c2ecf20Sopenharmony_ci * The checking of HCI_AUTO_OFF is not needed in this 8798c2ecf20Sopenharmony_ci * case since it will have been cleared already when 8808c2ecf20Sopenharmony_ci * opening the user channel. 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ci hci_dev_do_close(hdev); 8838c2ecf20Sopenharmony_ci hci_dev_clear_flag(hdev, HCI_USER_CHANNEL); 8848c2ecf20Sopenharmony_ci mgmt_index_added(hdev); 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci atomic_dec(&hdev->promisc); 8888c2ecf20Sopenharmony_ci hci_dev_put(hdev); 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci sock_orphan(sk); 8928c2ecf20Sopenharmony_ci release_sock(sk); 8938c2ecf20Sopenharmony_ci sock_put(sk); 8948c2ecf20Sopenharmony_ci return 0; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int hci_sock_reject_list_add(struct hci_dev *hdev, void __user *arg) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci bdaddr_t bdaddr; 9008c2ecf20Sopenharmony_ci int err; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) 9038c2ecf20Sopenharmony_ci return -EFAULT; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci hci_dev_lock(hdev); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci err = hci_bdaddr_list_add(&hdev->reject_list, &bdaddr, BDADDR_BREDR); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci hci_dev_unlock(hdev); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci return err; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic int hci_sock_reject_list_del(struct hci_dev *hdev, void __user *arg) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci bdaddr_t bdaddr; 9178c2ecf20Sopenharmony_ci int err; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (copy_from_user(&bdaddr, arg, sizeof(bdaddr))) 9208c2ecf20Sopenharmony_ci return -EFAULT; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci hci_dev_lock(hdev); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci err = hci_bdaddr_list_del(&hdev->reject_list, &bdaddr, BDADDR_BREDR); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci hci_dev_unlock(hdev); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci return err; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci/* Ioctls that require bound socket */ 9328c2ecf20Sopenharmony_cistatic int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, 9338c2ecf20Sopenharmony_ci unsigned long arg) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci struct hci_dev *hdev = hci_hdev_from_sock(sk); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (IS_ERR(hdev)) 9388c2ecf20Sopenharmony_ci return PTR_ERR(hdev); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) 9418c2ecf20Sopenharmony_ci return -EBUSY; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) 9448c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci if (hdev->dev_type != HCI_PRIMARY) 9478c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci switch (cmd) { 9508c2ecf20Sopenharmony_ci case HCISETRAW: 9518c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 9528c2ecf20Sopenharmony_ci return -EPERM; 9538c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci case HCIGETCONNINFO: 9568c2ecf20Sopenharmony_ci return hci_get_conn_info(hdev, (void __user *)arg); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci case HCIGETAUTHINFO: 9598c2ecf20Sopenharmony_ci return hci_get_auth_info(hdev, (void __user *)arg); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci case HCIBLOCKADDR: 9628c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 9638c2ecf20Sopenharmony_ci return -EPERM; 9648c2ecf20Sopenharmony_ci return hci_sock_reject_list_add(hdev, (void __user *)arg); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci case HCIUNBLOCKADDR: 9678c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 9688c2ecf20Sopenharmony_ci return -EPERM; 9698c2ecf20Sopenharmony_ci return hci_sock_reject_list_del(hdev, (void __user *)arg); 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic int hci_sock_ioctl(struct socket *sock, unsigned int cmd, 9768c2ecf20Sopenharmony_ci unsigned long arg) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 9798c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 9808c2ecf20Sopenharmony_ci int err; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci BT_DBG("cmd %x arg %lx", cmd, arg); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* Make sure the cmd is valid before doing anything */ 9858c2ecf20Sopenharmony_ci switch (cmd) { 9868c2ecf20Sopenharmony_ci case HCIGETDEVLIST: 9878c2ecf20Sopenharmony_ci case HCIGETDEVINFO: 9888c2ecf20Sopenharmony_ci case HCIGETCONNLIST: 9898c2ecf20Sopenharmony_ci case HCIDEVUP: 9908c2ecf20Sopenharmony_ci case HCIDEVDOWN: 9918c2ecf20Sopenharmony_ci case HCIDEVRESET: 9928c2ecf20Sopenharmony_ci case HCIDEVRESTAT: 9938c2ecf20Sopenharmony_ci case HCISETSCAN: 9948c2ecf20Sopenharmony_ci case HCISETAUTH: 9958c2ecf20Sopenharmony_ci case HCISETENCRYPT: 9968c2ecf20Sopenharmony_ci case HCISETPTYPE: 9978c2ecf20Sopenharmony_ci case HCISETLINKPOL: 9988c2ecf20Sopenharmony_ci case HCISETLINKMODE: 9998c2ecf20Sopenharmony_ci case HCISETACLMTU: 10008c2ecf20Sopenharmony_ci case HCISETSCOMTU: 10018c2ecf20Sopenharmony_ci case HCIINQUIRY: 10028c2ecf20Sopenharmony_ci case HCISETRAW: 10038c2ecf20Sopenharmony_ci case HCIGETCONNINFO: 10048c2ecf20Sopenharmony_ci case HCIGETAUTHINFO: 10058c2ecf20Sopenharmony_ci case HCIBLOCKADDR: 10068c2ecf20Sopenharmony_ci case HCIUNBLOCKADDR: 10078c2ecf20Sopenharmony_ci break; 10088c2ecf20Sopenharmony_ci default: 10098c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci lock_sock(sk); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { 10158c2ecf20Sopenharmony_ci err = -EBADFD; 10168c2ecf20Sopenharmony_ci goto done; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci /* When calling an ioctl on an unbound raw socket, then ensure 10208c2ecf20Sopenharmony_ci * that the monitor gets informed. Ensure that the resulting event 10218c2ecf20Sopenharmony_ci * is only send once by checking if the cookie exists or not. The 10228c2ecf20Sopenharmony_ci * socket cookie will be only ever generated once for the lifetime 10238c2ecf20Sopenharmony_ci * of a given socket. 10248c2ecf20Sopenharmony_ci */ 10258c2ecf20Sopenharmony_ci if (hci_sock_gen_cookie(sk)) { 10268c2ecf20Sopenharmony_ci struct sk_buff *skb; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* Perform careful checks before setting the HCI_SOCK_TRUSTED 10298c2ecf20Sopenharmony_ci * flag. Make sure that not only the current task but also 10308c2ecf20Sopenharmony_ci * the socket opener has the required capability, since 10318c2ecf20Sopenharmony_ci * privileged programs can be tricked into making ioctl calls 10328c2ecf20Sopenharmony_ci * on HCI sockets, and the socket should not be marked as 10338c2ecf20Sopenharmony_ci * trusted simply because the ioctl caller is privileged. 10348c2ecf20Sopenharmony_ci */ 10358c2ecf20Sopenharmony_ci if (sk_capable(sk, CAP_NET_ADMIN)) 10368c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_SOCK_TRUSTED); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci /* Send event to monitor */ 10398c2ecf20Sopenharmony_ci skb = create_monitor_ctrl_open(sk); 10408c2ecf20Sopenharmony_ci if (skb) { 10418c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 10428c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 10438c2ecf20Sopenharmony_ci kfree_skb(skb); 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci release_sock(sk); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci switch (cmd) { 10508c2ecf20Sopenharmony_ci case HCIGETDEVLIST: 10518c2ecf20Sopenharmony_ci return hci_get_dev_list(argp); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci case HCIGETDEVINFO: 10548c2ecf20Sopenharmony_ci return hci_get_dev_info(argp); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci case HCIGETCONNLIST: 10578c2ecf20Sopenharmony_ci return hci_get_conn_list(argp); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci case HCIDEVUP: 10608c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 10618c2ecf20Sopenharmony_ci return -EPERM; 10628c2ecf20Sopenharmony_ci return hci_dev_open(arg); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci case HCIDEVDOWN: 10658c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 10668c2ecf20Sopenharmony_ci return -EPERM; 10678c2ecf20Sopenharmony_ci return hci_dev_close(arg); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci case HCIDEVRESET: 10708c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 10718c2ecf20Sopenharmony_ci return -EPERM; 10728c2ecf20Sopenharmony_ci return hci_dev_reset(arg); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci case HCIDEVRESTAT: 10758c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 10768c2ecf20Sopenharmony_ci return -EPERM; 10778c2ecf20Sopenharmony_ci return hci_dev_reset_stat(arg); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci case HCISETSCAN: 10808c2ecf20Sopenharmony_ci case HCISETAUTH: 10818c2ecf20Sopenharmony_ci case HCISETENCRYPT: 10828c2ecf20Sopenharmony_ci case HCISETPTYPE: 10838c2ecf20Sopenharmony_ci case HCISETLINKPOL: 10848c2ecf20Sopenharmony_ci case HCISETLINKMODE: 10858c2ecf20Sopenharmony_ci case HCISETACLMTU: 10868c2ecf20Sopenharmony_ci case HCISETSCOMTU: 10878c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 10888c2ecf20Sopenharmony_ci return -EPERM; 10898c2ecf20Sopenharmony_ci return hci_dev_cmd(cmd, argp); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci case HCIINQUIRY: 10928c2ecf20Sopenharmony_ci return hci_inquiry(argp); 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci lock_sock(sk); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci err = hci_sock_bound_ioctl(sk, cmd, arg); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cidone: 11008c2ecf20Sopenharmony_ci release_sock(sk); 11018c2ecf20Sopenharmony_ci return err; 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 11058c2ecf20Sopenharmony_cistatic int hci_sock_compat_ioctl(struct socket *sock, unsigned int cmd, 11068c2ecf20Sopenharmony_ci unsigned long arg) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci switch (cmd) { 11098c2ecf20Sopenharmony_ci case HCIDEVUP: 11108c2ecf20Sopenharmony_ci case HCIDEVDOWN: 11118c2ecf20Sopenharmony_ci case HCIDEVRESET: 11128c2ecf20Sopenharmony_ci case HCIDEVRESTAT: 11138c2ecf20Sopenharmony_ci return hci_sock_ioctl(sock, cmd, arg); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci return hci_sock_ioctl(sock, cmd, (unsigned long)compat_ptr(arg)); 11178c2ecf20Sopenharmony_ci} 11188c2ecf20Sopenharmony_ci#endif 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic int hci_sock_bind(struct socket *sock, struct sockaddr *addr, 11218c2ecf20Sopenharmony_ci int addr_len) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct sockaddr_hci haddr; 11248c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 11258c2ecf20Sopenharmony_ci struct hci_dev *hdev = NULL; 11268c2ecf20Sopenharmony_ci struct sk_buff *skb; 11278c2ecf20Sopenharmony_ci int len, err = 0; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci BT_DBG("sock %p sk %p", sock, sk); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (!addr) 11328c2ecf20Sopenharmony_ci return -EINVAL; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci memset(&haddr, 0, sizeof(haddr)); 11358c2ecf20Sopenharmony_ci len = min_t(unsigned int, sizeof(haddr), addr_len); 11368c2ecf20Sopenharmony_ci memcpy(&haddr, addr, len); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (haddr.hci_family != AF_BLUETOOTH) 11398c2ecf20Sopenharmony_ci return -EINVAL; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci lock_sock(sk); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci /* Allow detaching from dead device and attaching to alive device, if 11448c2ecf20Sopenharmony_ci * the caller wants to re-bind (instead of close) this socket in 11458c2ecf20Sopenharmony_ci * response to hci_sock_dev_event(HCI_DEV_UNREG) notification. 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_ci hdev = hci_pi(sk)->hdev; 11488c2ecf20Sopenharmony_ci if (hdev && hci_dev_test_flag(hdev, HCI_UNREGISTER)) { 11498c2ecf20Sopenharmony_ci hci_pi(sk)->hdev = NULL; 11508c2ecf20Sopenharmony_ci sk->sk_state = BT_OPEN; 11518c2ecf20Sopenharmony_ci hci_dev_put(hdev); 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci hdev = NULL; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (sk->sk_state == BT_BOUND) { 11568c2ecf20Sopenharmony_ci err = -EALREADY; 11578c2ecf20Sopenharmony_ci goto done; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci switch (haddr.hci_channel) { 11618c2ecf20Sopenharmony_ci case HCI_CHANNEL_RAW: 11628c2ecf20Sopenharmony_ci if (hci_pi(sk)->hdev) { 11638c2ecf20Sopenharmony_ci err = -EALREADY; 11648c2ecf20Sopenharmony_ci goto done; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (haddr.hci_dev != HCI_DEV_NONE) { 11688c2ecf20Sopenharmony_ci hdev = hci_dev_get(haddr.hci_dev); 11698c2ecf20Sopenharmony_ci if (!hdev) { 11708c2ecf20Sopenharmony_ci err = -ENODEV; 11718c2ecf20Sopenharmony_ci goto done; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci atomic_inc(&hdev->promisc); 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci hci_pi(sk)->channel = haddr.hci_channel; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (!hci_sock_gen_cookie(sk)) { 11808c2ecf20Sopenharmony_ci /* In the case when a cookie has already been assigned, 11818c2ecf20Sopenharmony_ci * then there has been already an ioctl issued against 11828c2ecf20Sopenharmony_ci * an unbound socket and with that triggerd an open 11838c2ecf20Sopenharmony_ci * notification. Send a close notification first to 11848c2ecf20Sopenharmony_ci * allow the state transition to bounded. 11858c2ecf20Sopenharmony_ci */ 11868c2ecf20Sopenharmony_ci skb = create_monitor_ctrl_close(sk); 11878c2ecf20Sopenharmony_ci if (skb) { 11888c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 11898c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 11908c2ecf20Sopenharmony_ci kfree_skb(skb); 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci if (capable(CAP_NET_ADMIN)) 11958c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_SOCK_TRUSTED); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci hci_pi(sk)->hdev = hdev; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* Send event to monitor */ 12008c2ecf20Sopenharmony_ci skb = create_monitor_ctrl_open(sk); 12018c2ecf20Sopenharmony_ci if (skb) { 12028c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 12038c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 12048c2ecf20Sopenharmony_ci kfree_skb(skb); 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci break; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci case HCI_CHANNEL_USER: 12098c2ecf20Sopenharmony_ci if (hci_pi(sk)->hdev) { 12108c2ecf20Sopenharmony_ci err = -EALREADY; 12118c2ecf20Sopenharmony_ci goto done; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (haddr.hci_dev == HCI_DEV_NONE) { 12158c2ecf20Sopenharmony_ci err = -EINVAL; 12168c2ecf20Sopenharmony_ci goto done; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) { 12208c2ecf20Sopenharmony_ci err = -EPERM; 12218c2ecf20Sopenharmony_ci goto done; 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci hdev = hci_dev_get(haddr.hci_dev); 12258c2ecf20Sopenharmony_ci if (!hdev) { 12268c2ecf20Sopenharmony_ci err = -ENODEV; 12278c2ecf20Sopenharmony_ci goto done; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (test_bit(HCI_INIT, &hdev->flags) || 12318c2ecf20Sopenharmony_ci hci_dev_test_flag(hdev, HCI_SETUP) || 12328c2ecf20Sopenharmony_ci hci_dev_test_flag(hdev, HCI_CONFIG) || 12338c2ecf20Sopenharmony_ci (!hci_dev_test_flag(hdev, HCI_AUTO_OFF) && 12348c2ecf20Sopenharmony_ci test_bit(HCI_UP, &hdev->flags))) { 12358c2ecf20Sopenharmony_ci err = -EBUSY; 12368c2ecf20Sopenharmony_ci hci_dev_put(hdev); 12378c2ecf20Sopenharmony_ci goto done; 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (hci_dev_test_and_set_flag(hdev, HCI_USER_CHANNEL)) { 12418c2ecf20Sopenharmony_ci err = -EUSERS; 12428c2ecf20Sopenharmony_ci hci_dev_put(hdev); 12438c2ecf20Sopenharmony_ci goto done; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci mgmt_index_removed(hdev); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci err = hci_dev_open(hdev->id); 12498c2ecf20Sopenharmony_ci if (err) { 12508c2ecf20Sopenharmony_ci if (err == -EALREADY) { 12518c2ecf20Sopenharmony_ci /* In case the transport is already up and 12528c2ecf20Sopenharmony_ci * running, clear the error here. 12538c2ecf20Sopenharmony_ci * 12548c2ecf20Sopenharmony_ci * This can happen when opening a user 12558c2ecf20Sopenharmony_ci * channel and HCI_AUTO_OFF grace period 12568c2ecf20Sopenharmony_ci * is still active. 12578c2ecf20Sopenharmony_ci */ 12588c2ecf20Sopenharmony_ci err = 0; 12598c2ecf20Sopenharmony_ci } else { 12608c2ecf20Sopenharmony_ci hci_dev_clear_flag(hdev, HCI_USER_CHANNEL); 12618c2ecf20Sopenharmony_ci mgmt_index_added(hdev); 12628c2ecf20Sopenharmony_ci hci_dev_put(hdev); 12638c2ecf20Sopenharmony_ci goto done; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci hci_pi(sk)->channel = haddr.hci_channel; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci if (!hci_sock_gen_cookie(sk)) { 12708c2ecf20Sopenharmony_ci /* In the case when a cookie has already been assigned, 12718c2ecf20Sopenharmony_ci * this socket will transition from a raw socket into 12728c2ecf20Sopenharmony_ci * a user channel socket. For a clean transition, send 12738c2ecf20Sopenharmony_ci * the close notification first. 12748c2ecf20Sopenharmony_ci */ 12758c2ecf20Sopenharmony_ci skb = create_monitor_ctrl_close(sk); 12768c2ecf20Sopenharmony_ci if (skb) { 12778c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 12788c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 12798c2ecf20Sopenharmony_ci kfree_skb(skb); 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* The user channel is restricted to CAP_NET_ADMIN 12848c2ecf20Sopenharmony_ci * capabilities and with that implicitly trusted. 12858c2ecf20Sopenharmony_ci */ 12868c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_SOCK_TRUSTED); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci hci_pi(sk)->hdev = hdev; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci /* Send event to monitor */ 12918c2ecf20Sopenharmony_ci skb = create_monitor_ctrl_open(sk); 12928c2ecf20Sopenharmony_ci if (skb) { 12938c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 12948c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 12958c2ecf20Sopenharmony_ci kfree_skb(skb); 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci atomic_inc(&hdev->promisc); 12998c2ecf20Sopenharmony_ci break; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci case HCI_CHANNEL_MONITOR: 13028c2ecf20Sopenharmony_ci if (haddr.hci_dev != HCI_DEV_NONE) { 13038c2ecf20Sopenharmony_ci err = -EINVAL; 13048c2ecf20Sopenharmony_ci goto done; 13058c2ecf20Sopenharmony_ci } 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci if (!capable(CAP_NET_RAW)) { 13088c2ecf20Sopenharmony_ci err = -EPERM; 13098c2ecf20Sopenharmony_ci goto done; 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci hci_pi(sk)->channel = haddr.hci_channel; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* The monitor interface is restricted to CAP_NET_RAW 13158c2ecf20Sopenharmony_ci * capabilities and with that implicitly trusted. 13168c2ecf20Sopenharmony_ci */ 13178c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_SOCK_TRUSTED); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci send_monitor_note(sk, "Linux version %s (%s)", 13208c2ecf20Sopenharmony_ci init_utsname()->release, 13218c2ecf20Sopenharmony_ci init_utsname()->machine); 13228c2ecf20Sopenharmony_ci send_monitor_note(sk, "Bluetooth subsystem version %u.%u", 13238c2ecf20Sopenharmony_ci BT_SUBSYS_VERSION, BT_SUBSYS_REVISION); 13248c2ecf20Sopenharmony_ci send_monitor_replay(sk); 13258c2ecf20Sopenharmony_ci send_monitor_control_replay(sk); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci atomic_inc(&monitor_promisc); 13288c2ecf20Sopenharmony_ci break; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci case HCI_CHANNEL_LOGGING: 13318c2ecf20Sopenharmony_ci if (haddr.hci_dev != HCI_DEV_NONE) { 13328c2ecf20Sopenharmony_ci err = -EINVAL; 13338c2ecf20Sopenharmony_ci goto done; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) { 13378c2ecf20Sopenharmony_ci err = -EPERM; 13388c2ecf20Sopenharmony_ci goto done; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci hci_pi(sk)->channel = haddr.hci_channel; 13428c2ecf20Sopenharmony_ci break; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci default: 13458c2ecf20Sopenharmony_ci if (!hci_mgmt_chan_find(haddr.hci_channel)) { 13468c2ecf20Sopenharmony_ci err = -EINVAL; 13478c2ecf20Sopenharmony_ci goto done; 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci if (haddr.hci_dev != HCI_DEV_NONE) { 13518c2ecf20Sopenharmony_ci err = -EINVAL; 13528c2ecf20Sopenharmony_ci goto done; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci /* Users with CAP_NET_ADMIN capabilities are allowed 13568c2ecf20Sopenharmony_ci * access to all management commands and events. For 13578c2ecf20Sopenharmony_ci * untrusted users the interface is restricted and 13588c2ecf20Sopenharmony_ci * also only untrusted events are sent. 13598c2ecf20Sopenharmony_ci */ 13608c2ecf20Sopenharmony_ci if (capable(CAP_NET_ADMIN)) 13618c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_SOCK_TRUSTED); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci hci_pi(sk)->channel = haddr.hci_channel; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* At the moment the index and unconfigured index events 13668c2ecf20Sopenharmony_ci * are enabled unconditionally. Setting them on each 13678c2ecf20Sopenharmony_ci * socket when binding keeps this functionality. They 13688c2ecf20Sopenharmony_ci * however might be cleared later and then sending of these 13698c2ecf20Sopenharmony_ci * events will be disabled, but that is then intentional. 13708c2ecf20Sopenharmony_ci * 13718c2ecf20Sopenharmony_ci * This also enables generic events that are safe to be 13728c2ecf20Sopenharmony_ci * received by untrusted users. Example for such events 13738c2ecf20Sopenharmony_ci * are changes to settings, class of device, name etc. 13748c2ecf20Sopenharmony_ci */ 13758c2ecf20Sopenharmony_ci if (hci_pi(sk)->channel == HCI_CHANNEL_CONTROL) { 13768c2ecf20Sopenharmony_ci if (!hci_sock_gen_cookie(sk)) { 13778c2ecf20Sopenharmony_ci /* In the case when a cookie has already been 13788c2ecf20Sopenharmony_ci * assigned, this socket will transtion from 13798c2ecf20Sopenharmony_ci * a raw socket into a control socket. To 13808c2ecf20Sopenharmony_ci * allow for a clean transtion, send the 13818c2ecf20Sopenharmony_ci * close notification first. 13828c2ecf20Sopenharmony_ci */ 13838c2ecf20Sopenharmony_ci skb = create_monitor_ctrl_close(sk); 13848c2ecf20Sopenharmony_ci if (skb) { 13858c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 13868c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 13878c2ecf20Sopenharmony_ci kfree_skb(skb); 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci /* Send event to monitor */ 13928c2ecf20Sopenharmony_ci skb = create_monitor_ctrl_open(sk); 13938c2ecf20Sopenharmony_ci if (skb) { 13948c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 13958c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 13968c2ecf20Sopenharmony_ci kfree_skb(skb); 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_MGMT_INDEX_EVENTS); 14008c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS); 14018c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_MGMT_OPTION_EVENTS); 14028c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_MGMT_SETTING_EVENTS); 14038c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS); 14048c2ecf20Sopenharmony_ci hci_sock_set_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS); 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci break; 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci sk->sk_state = BT_BOUND; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_cidone: 14128c2ecf20Sopenharmony_ci release_sock(sk); 14138c2ecf20Sopenharmony_ci return err; 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_cistatic int hci_sock_getname(struct socket *sock, struct sockaddr *addr, 14178c2ecf20Sopenharmony_ci int peer) 14188c2ecf20Sopenharmony_ci{ 14198c2ecf20Sopenharmony_ci struct sockaddr_hci *haddr = (struct sockaddr_hci *)addr; 14208c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 14218c2ecf20Sopenharmony_ci struct hci_dev *hdev; 14228c2ecf20Sopenharmony_ci int err = 0; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci BT_DBG("sock %p sk %p", sock, sk); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (peer) 14278c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci lock_sock(sk); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci hdev = hci_hdev_from_sock(sk); 14328c2ecf20Sopenharmony_ci if (IS_ERR(hdev)) { 14338c2ecf20Sopenharmony_ci err = PTR_ERR(hdev); 14348c2ecf20Sopenharmony_ci goto done; 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci haddr->hci_family = AF_BLUETOOTH; 14388c2ecf20Sopenharmony_ci haddr->hci_dev = hdev->id; 14398c2ecf20Sopenharmony_ci haddr->hci_channel= hci_pi(sk)->channel; 14408c2ecf20Sopenharmony_ci err = sizeof(*haddr); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_cidone: 14438c2ecf20Sopenharmony_ci release_sock(sk); 14448c2ecf20Sopenharmony_ci return err; 14458c2ecf20Sopenharmony_ci} 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_cistatic void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, 14488c2ecf20Sopenharmony_ci struct sk_buff *skb) 14498c2ecf20Sopenharmony_ci{ 14508c2ecf20Sopenharmony_ci __u8 mask = hci_pi(sk)->cmsg_mask; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci if (mask & HCI_CMSG_DIR) { 14538c2ecf20Sopenharmony_ci int incoming = bt_cb(skb)->incoming; 14548c2ecf20Sopenharmony_ci put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming), 14558c2ecf20Sopenharmony_ci &incoming); 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci if (mask & HCI_CMSG_TSTAMP) { 14598c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 14608c2ecf20Sopenharmony_ci struct old_timeval32 ctv; 14618c2ecf20Sopenharmony_ci#endif 14628c2ecf20Sopenharmony_ci struct __kernel_old_timeval tv; 14638c2ecf20Sopenharmony_ci void *data; 14648c2ecf20Sopenharmony_ci int len; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci skb_get_timestamp(skb, &tv); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci data = &tv; 14698c2ecf20Sopenharmony_ci len = sizeof(tv); 14708c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 14718c2ecf20Sopenharmony_ci if (!COMPAT_USE_64BIT_TIME && 14728c2ecf20Sopenharmony_ci (msg->msg_flags & MSG_CMSG_COMPAT)) { 14738c2ecf20Sopenharmony_ci ctv.tv_sec = tv.tv_sec; 14748c2ecf20Sopenharmony_ci ctv.tv_usec = tv.tv_usec; 14758c2ecf20Sopenharmony_ci data = &ctv; 14768c2ecf20Sopenharmony_ci len = sizeof(ctv); 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci#endif 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, len, data); 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci} 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cistatic int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, 14858c2ecf20Sopenharmony_ci size_t len, int flags) 14868c2ecf20Sopenharmony_ci{ 14878c2ecf20Sopenharmony_ci int noblock = flags & MSG_DONTWAIT; 14888c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 14898c2ecf20Sopenharmony_ci struct sk_buff *skb; 14908c2ecf20Sopenharmony_ci int copied, err; 14918c2ecf20Sopenharmony_ci unsigned int skblen; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci BT_DBG("sock %p, sk %p", sock, sk); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci if (flags & MSG_OOB) 14968c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (hci_pi(sk)->channel == HCI_CHANNEL_LOGGING) 14998c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if (sk->sk_state == BT_CLOSED) 15028c2ecf20Sopenharmony_ci return 0; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci skb = skb_recv_datagram(sk, flags, noblock, &err); 15058c2ecf20Sopenharmony_ci if (!skb) 15068c2ecf20Sopenharmony_ci return err; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci skblen = skb->len; 15098c2ecf20Sopenharmony_ci copied = skb->len; 15108c2ecf20Sopenharmony_ci if (len < copied) { 15118c2ecf20Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 15128c2ecf20Sopenharmony_ci copied = len; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci skb_reset_transport_header(skb); 15168c2ecf20Sopenharmony_ci err = skb_copy_datagram_msg(skb, 0, msg, copied); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci switch (hci_pi(sk)->channel) { 15198c2ecf20Sopenharmony_ci case HCI_CHANNEL_RAW: 15208c2ecf20Sopenharmony_ci hci_sock_cmsg(sk, msg, skb); 15218c2ecf20Sopenharmony_ci break; 15228c2ecf20Sopenharmony_ci case HCI_CHANNEL_USER: 15238c2ecf20Sopenharmony_ci case HCI_CHANNEL_MONITOR: 15248c2ecf20Sopenharmony_ci sock_recv_timestamp(msg, sk, skb); 15258c2ecf20Sopenharmony_ci break; 15268c2ecf20Sopenharmony_ci default: 15278c2ecf20Sopenharmony_ci if (hci_mgmt_chan_find(hci_pi(sk)->channel)) 15288c2ecf20Sopenharmony_ci sock_recv_timestamp(msg, sk, skb); 15298c2ecf20Sopenharmony_ci break; 15308c2ecf20Sopenharmony_ci } 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci skb_free_datagram(sk, skb); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (flags & MSG_TRUNC) 15358c2ecf20Sopenharmony_ci copied = skblen; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci return err ? : copied; 15388c2ecf20Sopenharmony_ci} 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_cistatic int hci_mgmt_cmd(struct hci_mgmt_chan *chan, struct sock *sk, 15418c2ecf20Sopenharmony_ci struct msghdr *msg, size_t msglen) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci void *buf; 15448c2ecf20Sopenharmony_ci u8 *cp; 15458c2ecf20Sopenharmony_ci struct mgmt_hdr *hdr; 15468c2ecf20Sopenharmony_ci u16 opcode, index, len; 15478c2ecf20Sopenharmony_ci struct hci_dev *hdev = NULL; 15488c2ecf20Sopenharmony_ci const struct hci_mgmt_handler *handler; 15498c2ecf20Sopenharmony_ci bool var_len, no_hdev; 15508c2ecf20Sopenharmony_ci int err; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci BT_DBG("got %zu bytes", msglen); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci if (msglen < sizeof(*hdr)) 15558c2ecf20Sopenharmony_ci return -EINVAL; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci buf = kmalloc(msglen, GFP_KERNEL); 15588c2ecf20Sopenharmony_ci if (!buf) 15598c2ecf20Sopenharmony_ci return -ENOMEM; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (memcpy_from_msg(buf, msg, msglen)) { 15628c2ecf20Sopenharmony_ci err = -EFAULT; 15638c2ecf20Sopenharmony_ci goto done; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci hdr = buf; 15678c2ecf20Sopenharmony_ci opcode = __le16_to_cpu(hdr->opcode); 15688c2ecf20Sopenharmony_ci index = __le16_to_cpu(hdr->index); 15698c2ecf20Sopenharmony_ci len = __le16_to_cpu(hdr->len); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci if (len != msglen - sizeof(*hdr)) { 15728c2ecf20Sopenharmony_ci err = -EINVAL; 15738c2ecf20Sopenharmony_ci goto done; 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci if (chan->channel == HCI_CHANNEL_CONTROL) { 15778c2ecf20Sopenharmony_ci struct sk_buff *skb; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci /* Send event to monitor */ 15808c2ecf20Sopenharmony_ci skb = create_monitor_ctrl_command(sk, index, opcode, len, 15818c2ecf20Sopenharmony_ci buf + sizeof(*hdr)); 15828c2ecf20Sopenharmony_ci if (skb) { 15838c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, 15848c2ecf20Sopenharmony_ci HCI_SOCK_TRUSTED, NULL); 15858c2ecf20Sopenharmony_ci kfree_skb(skb); 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (opcode >= chan->handler_count || 15908c2ecf20Sopenharmony_ci chan->handlers[opcode].func == NULL) { 15918c2ecf20Sopenharmony_ci BT_DBG("Unknown op %u", opcode); 15928c2ecf20Sopenharmony_ci err = mgmt_cmd_status(sk, index, opcode, 15938c2ecf20Sopenharmony_ci MGMT_STATUS_UNKNOWN_COMMAND); 15948c2ecf20Sopenharmony_ci goto done; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci handler = &chan->handlers[opcode]; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci if (!hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) && 16008c2ecf20Sopenharmony_ci !(handler->flags & HCI_MGMT_UNTRUSTED)) { 16018c2ecf20Sopenharmony_ci err = mgmt_cmd_status(sk, index, opcode, 16028c2ecf20Sopenharmony_ci MGMT_STATUS_PERMISSION_DENIED); 16038c2ecf20Sopenharmony_ci goto done; 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (index != MGMT_INDEX_NONE) { 16078c2ecf20Sopenharmony_ci hdev = hci_dev_get(index); 16088c2ecf20Sopenharmony_ci if (!hdev) { 16098c2ecf20Sopenharmony_ci err = mgmt_cmd_status(sk, index, opcode, 16108c2ecf20Sopenharmony_ci MGMT_STATUS_INVALID_INDEX); 16118c2ecf20Sopenharmony_ci goto done; 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci if (hci_dev_test_flag(hdev, HCI_SETUP) || 16158c2ecf20Sopenharmony_ci hci_dev_test_flag(hdev, HCI_CONFIG) || 16168c2ecf20Sopenharmony_ci hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) { 16178c2ecf20Sopenharmony_ci err = mgmt_cmd_status(sk, index, opcode, 16188c2ecf20Sopenharmony_ci MGMT_STATUS_INVALID_INDEX); 16198c2ecf20Sopenharmony_ci goto done; 16208c2ecf20Sopenharmony_ci } 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) && 16238c2ecf20Sopenharmony_ci !(handler->flags & HCI_MGMT_UNCONFIGURED)) { 16248c2ecf20Sopenharmony_ci err = mgmt_cmd_status(sk, index, opcode, 16258c2ecf20Sopenharmony_ci MGMT_STATUS_INVALID_INDEX); 16268c2ecf20Sopenharmony_ci goto done; 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci if (!(handler->flags & HCI_MGMT_HDEV_OPTIONAL)) { 16318c2ecf20Sopenharmony_ci no_hdev = (handler->flags & HCI_MGMT_NO_HDEV); 16328c2ecf20Sopenharmony_ci if (no_hdev != !hdev) { 16338c2ecf20Sopenharmony_ci err = mgmt_cmd_status(sk, index, opcode, 16348c2ecf20Sopenharmony_ci MGMT_STATUS_INVALID_INDEX); 16358c2ecf20Sopenharmony_ci goto done; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci var_len = (handler->flags & HCI_MGMT_VAR_LEN); 16408c2ecf20Sopenharmony_ci if ((var_len && len < handler->data_len) || 16418c2ecf20Sopenharmony_ci (!var_len && len != handler->data_len)) { 16428c2ecf20Sopenharmony_ci err = mgmt_cmd_status(sk, index, opcode, 16438c2ecf20Sopenharmony_ci MGMT_STATUS_INVALID_PARAMS); 16448c2ecf20Sopenharmony_ci goto done; 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci if (hdev && chan->hdev_init) 16488c2ecf20Sopenharmony_ci chan->hdev_init(sk, hdev); 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci cp = buf + sizeof(*hdr); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci err = handler->func(sk, hdev, cp, len); 16538c2ecf20Sopenharmony_ci if (err < 0) 16548c2ecf20Sopenharmony_ci goto done; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci err = msglen; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cidone: 16598c2ecf20Sopenharmony_ci if (hdev) 16608c2ecf20Sopenharmony_ci hci_dev_put(hdev); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci kfree(buf); 16638c2ecf20Sopenharmony_ci return err; 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_cistatic int hci_logging_frame(struct sock *sk, struct msghdr *msg, int len) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci struct hci_mon_hdr *hdr; 16698c2ecf20Sopenharmony_ci struct sk_buff *skb; 16708c2ecf20Sopenharmony_ci struct hci_dev *hdev; 16718c2ecf20Sopenharmony_ci u16 index; 16728c2ecf20Sopenharmony_ci int err; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci /* The logging frame consists at minimum of the standard header, 16758c2ecf20Sopenharmony_ci * the priority byte, the ident length byte and at least one string 16768c2ecf20Sopenharmony_ci * terminator NUL byte. Anything shorter are invalid packets. 16778c2ecf20Sopenharmony_ci */ 16788c2ecf20Sopenharmony_ci if (len < sizeof(*hdr) + 3) 16798c2ecf20Sopenharmony_ci return -EINVAL; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err); 16828c2ecf20Sopenharmony_ci if (!skb) 16838c2ecf20Sopenharmony_ci return err; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci if (memcpy_from_msg(skb_put(skb, len), msg, len)) { 16868c2ecf20Sopenharmony_ci err = -EFAULT; 16878c2ecf20Sopenharmony_ci goto drop; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci hdr = (void *)skb->data; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci if (__le16_to_cpu(hdr->len) != len - sizeof(*hdr)) { 16938c2ecf20Sopenharmony_ci err = -EINVAL; 16948c2ecf20Sopenharmony_ci goto drop; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci if (__le16_to_cpu(hdr->opcode) == 0x0000) { 16988c2ecf20Sopenharmony_ci __u8 priority = skb->data[sizeof(*hdr)]; 16998c2ecf20Sopenharmony_ci __u8 ident_len = skb->data[sizeof(*hdr) + 1]; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci /* Only the priorities 0-7 are valid and with that any other 17028c2ecf20Sopenharmony_ci * value results in an invalid packet. 17038c2ecf20Sopenharmony_ci * 17048c2ecf20Sopenharmony_ci * The priority byte is followed by an ident length byte and 17058c2ecf20Sopenharmony_ci * the NUL terminated ident string. Check that the ident 17068c2ecf20Sopenharmony_ci * length is not overflowing the packet and also that the 17078c2ecf20Sopenharmony_ci * ident string itself is NUL terminated. In case the ident 17088c2ecf20Sopenharmony_ci * length is zero, the length value actually doubles as NUL 17098c2ecf20Sopenharmony_ci * terminator identifier. 17108c2ecf20Sopenharmony_ci * 17118c2ecf20Sopenharmony_ci * The message follows the ident string (if present) and 17128c2ecf20Sopenharmony_ci * must be NUL terminated. Otherwise it is not a valid packet. 17138c2ecf20Sopenharmony_ci */ 17148c2ecf20Sopenharmony_ci if (priority > 7 || skb->data[len - 1] != 0x00 || 17158c2ecf20Sopenharmony_ci ident_len > len - sizeof(*hdr) - 3 || 17168c2ecf20Sopenharmony_ci skb->data[sizeof(*hdr) + ident_len + 1] != 0x00) { 17178c2ecf20Sopenharmony_ci err = -EINVAL; 17188c2ecf20Sopenharmony_ci goto drop; 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci } else { 17218c2ecf20Sopenharmony_ci err = -EINVAL; 17228c2ecf20Sopenharmony_ci goto drop; 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci index = __le16_to_cpu(hdr->index); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci if (index != MGMT_INDEX_NONE) { 17288c2ecf20Sopenharmony_ci hdev = hci_dev_get(index); 17298c2ecf20Sopenharmony_ci if (!hdev) { 17308c2ecf20Sopenharmony_ci err = -ENODEV; 17318c2ecf20Sopenharmony_ci goto drop; 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci } else { 17348c2ecf20Sopenharmony_ci hdev = NULL; 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci hdr->opcode = cpu_to_le16(HCI_MON_USER_LOGGING); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, HCI_SOCK_TRUSTED, NULL); 17408c2ecf20Sopenharmony_ci err = len; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci if (hdev) 17438c2ecf20Sopenharmony_ci hci_dev_put(hdev); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_cidrop: 17468c2ecf20Sopenharmony_ci kfree_skb(skb); 17478c2ecf20Sopenharmony_ci return err; 17488c2ecf20Sopenharmony_ci} 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_cistatic int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, 17518c2ecf20Sopenharmony_ci size_t len) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 17548c2ecf20Sopenharmony_ci struct hci_mgmt_chan *chan; 17558c2ecf20Sopenharmony_ci struct hci_dev *hdev; 17568c2ecf20Sopenharmony_ci struct sk_buff *skb; 17578c2ecf20Sopenharmony_ci int err; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci BT_DBG("sock %p sk %p", sock, sk); 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci if (msg->msg_flags & MSG_OOB) 17628c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE| 17658c2ecf20Sopenharmony_ci MSG_CMSG_COMPAT)) 17668c2ecf20Sopenharmony_ci return -EINVAL; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci if (len < 4 || len > HCI_MAX_FRAME_SIZE) 17698c2ecf20Sopenharmony_ci return -EINVAL; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci lock_sock(sk); 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci switch (hci_pi(sk)->channel) { 17748c2ecf20Sopenharmony_ci case HCI_CHANNEL_RAW: 17758c2ecf20Sopenharmony_ci case HCI_CHANNEL_USER: 17768c2ecf20Sopenharmony_ci break; 17778c2ecf20Sopenharmony_ci case HCI_CHANNEL_MONITOR: 17788c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 17798c2ecf20Sopenharmony_ci goto done; 17808c2ecf20Sopenharmony_ci case HCI_CHANNEL_LOGGING: 17818c2ecf20Sopenharmony_ci err = hci_logging_frame(sk, msg, len); 17828c2ecf20Sopenharmony_ci goto done; 17838c2ecf20Sopenharmony_ci default: 17848c2ecf20Sopenharmony_ci mutex_lock(&mgmt_chan_list_lock); 17858c2ecf20Sopenharmony_ci chan = __hci_mgmt_chan_find(hci_pi(sk)->channel); 17868c2ecf20Sopenharmony_ci if (chan) 17878c2ecf20Sopenharmony_ci err = hci_mgmt_cmd(chan, sk, msg, len); 17888c2ecf20Sopenharmony_ci else 17898c2ecf20Sopenharmony_ci err = -EINVAL; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci mutex_unlock(&mgmt_chan_list_lock); 17928c2ecf20Sopenharmony_ci goto done; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci hdev = hci_hdev_from_sock(sk); 17968c2ecf20Sopenharmony_ci if (IS_ERR(hdev)) { 17978c2ecf20Sopenharmony_ci err = PTR_ERR(hdev); 17988c2ecf20Sopenharmony_ci goto done; 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if (!test_bit(HCI_UP, &hdev->flags)) { 18028c2ecf20Sopenharmony_ci err = -ENETDOWN; 18038c2ecf20Sopenharmony_ci goto done; 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err); 18078c2ecf20Sopenharmony_ci if (!skb) 18088c2ecf20Sopenharmony_ci goto done; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci if (memcpy_from_msg(skb_put(skb, len), msg, len)) { 18118c2ecf20Sopenharmony_ci err = -EFAULT; 18128c2ecf20Sopenharmony_ci goto drop; 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) = skb->data[0]; 18168c2ecf20Sopenharmony_ci skb_pull(skb, 1); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci if (hci_pi(sk)->channel == HCI_CHANNEL_USER) { 18198c2ecf20Sopenharmony_ci /* No permission check is needed for user channel 18208c2ecf20Sopenharmony_ci * since that gets enforced when binding the socket. 18218c2ecf20Sopenharmony_ci * 18228c2ecf20Sopenharmony_ci * However check that the packet type is valid. 18238c2ecf20Sopenharmony_ci */ 18248c2ecf20Sopenharmony_ci if (hci_skb_pkt_type(skb) != HCI_COMMAND_PKT && 18258c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT && 18268c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_SCODATA_PKT && 18278c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_ISODATA_PKT) { 18288c2ecf20Sopenharmony_ci err = -EINVAL; 18298c2ecf20Sopenharmony_ci goto drop; 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci skb_queue_tail(&hdev->raw_q, skb); 18338c2ecf20Sopenharmony_ci queue_work(hdev->workqueue, &hdev->tx_work); 18348c2ecf20Sopenharmony_ci } else if (hci_skb_pkt_type(skb) == HCI_COMMAND_PKT) { 18358c2ecf20Sopenharmony_ci u16 opcode = get_unaligned_le16(skb->data); 18368c2ecf20Sopenharmony_ci u16 ogf = hci_opcode_ogf(opcode); 18378c2ecf20Sopenharmony_ci u16 ocf = hci_opcode_ocf(opcode); 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (((ogf > HCI_SFLT_MAX_OGF) || 18408c2ecf20Sopenharmony_ci !hci_test_bit(ocf & HCI_FLT_OCF_BITS, 18418c2ecf20Sopenharmony_ci &hci_sec_filter.ocf_mask[ogf])) && 18428c2ecf20Sopenharmony_ci !capable(CAP_NET_RAW)) { 18438c2ecf20Sopenharmony_ci err = -EPERM; 18448c2ecf20Sopenharmony_ci goto drop; 18458c2ecf20Sopenharmony_ci } 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci /* Since the opcode has already been extracted here, store 18488c2ecf20Sopenharmony_ci * a copy of the value for later use by the drivers. 18498c2ecf20Sopenharmony_ci */ 18508c2ecf20Sopenharmony_ci hci_skb_opcode(skb) = opcode; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci if (ogf == 0x3f) { 18538c2ecf20Sopenharmony_ci skb_queue_tail(&hdev->raw_q, skb); 18548c2ecf20Sopenharmony_ci queue_work(hdev->workqueue, &hdev->tx_work); 18558c2ecf20Sopenharmony_ci } else { 18568c2ecf20Sopenharmony_ci /* Stand-alone HCI commands must be flagged as 18578c2ecf20Sopenharmony_ci * single-command requests. 18588c2ecf20Sopenharmony_ci */ 18598c2ecf20Sopenharmony_ci bt_cb(skb)->hci.req_flags |= HCI_REQ_START; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci skb_queue_tail(&hdev->cmd_q, skb); 18628c2ecf20Sopenharmony_ci queue_work(hdev->workqueue, &hdev->cmd_work); 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci } else { 18658c2ecf20Sopenharmony_ci if (!capable(CAP_NET_RAW)) { 18668c2ecf20Sopenharmony_ci err = -EPERM; 18678c2ecf20Sopenharmony_ci goto drop; 18688c2ecf20Sopenharmony_ci } 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci if (hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT && 18718c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_SCODATA_PKT && 18728c2ecf20Sopenharmony_ci hci_skb_pkt_type(skb) != HCI_ISODATA_PKT) { 18738c2ecf20Sopenharmony_ci err = -EINVAL; 18748c2ecf20Sopenharmony_ci goto drop; 18758c2ecf20Sopenharmony_ci } 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci skb_queue_tail(&hdev->raw_q, skb); 18788c2ecf20Sopenharmony_ci queue_work(hdev->workqueue, &hdev->tx_work); 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci err = len; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_cidone: 18848c2ecf20Sopenharmony_ci release_sock(sk); 18858c2ecf20Sopenharmony_ci return err; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_cidrop: 18888c2ecf20Sopenharmony_ci kfree_skb(skb); 18898c2ecf20Sopenharmony_ci goto done; 18908c2ecf20Sopenharmony_ci} 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_cistatic int hci_sock_setsockopt(struct socket *sock, int level, int optname, 18938c2ecf20Sopenharmony_ci sockptr_t optval, unsigned int len) 18948c2ecf20Sopenharmony_ci{ 18958c2ecf20Sopenharmony_ci struct hci_ufilter uf = { .opcode = 0 }; 18968c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 18978c2ecf20Sopenharmony_ci int err = 0, opt = 0; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci BT_DBG("sk %p, opt %d", sk, optname); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci if (level != SOL_HCI) 19028c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci lock_sock(sk); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { 19078c2ecf20Sopenharmony_ci err = -EBADFD; 19088c2ecf20Sopenharmony_ci goto done; 19098c2ecf20Sopenharmony_ci } 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci switch (optname) { 19128c2ecf20Sopenharmony_ci case HCI_DATA_DIR: 19138c2ecf20Sopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(opt))) { 19148c2ecf20Sopenharmony_ci err = -EFAULT; 19158c2ecf20Sopenharmony_ci break; 19168c2ecf20Sopenharmony_ci } 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci if (opt) 19198c2ecf20Sopenharmony_ci hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR; 19208c2ecf20Sopenharmony_ci else 19218c2ecf20Sopenharmony_ci hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR; 19228c2ecf20Sopenharmony_ci break; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci case HCI_TIME_STAMP: 19258c2ecf20Sopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(opt))) { 19268c2ecf20Sopenharmony_ci err = -EFAULT; 19278c2ecf20Sopenharmony_ci break; 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci if (opt) 19318c2ecf20Sopenharmony_ci hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP; 19328c2ecf20Sopenharmony_ci else 19338c2ecf20Sopenharmony_ci hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP; 19348c2ecf20Sopenharmony_ci break; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci case HCI_FILTER: 19378c2ecf20Sopenharmony_ci { 19388c2ecf20Sopenharmony_ci struct hci_filter *f = &hci_pi(sk)->filter; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci uf.type_mask = f->type_mask; 19418c2ecf20Sopenharmony_ci uf.opcode = f->opcode; 19428c2ecf20Sopenharmony_ci uf.event_mask[0] = *((u32 *) f->event_mask + 0); 19438c2ecf20Sopenharmony_ci uf.event_mask[1] = *((u32 *) f->event_mask + 1); 19448c2ecf20Sopenharmony_ci } 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci len = min_t(unsigned int, len, sizeof(uf)); 19478c2ecf20Sopenharmony_ci if (copy_from_sockptr(&uf, optval, len)) { 19488c2ecf20Sopenharmony_ci err = -EFAULT; 19498c2ecf20Sopenharmony_ci break; 19508c2ecf20Sopenharmony_ci } 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci if (!capable(CAP_NET_RAW)) { 19538c2ecf20Sopenharmony_ci uf.type_mask &= hci_sec_filter.type_mask; 19548c2ecf20Sopenharmony_ci uf.event_mask[0] &= *((u32 *) hci_sec_filter.event_mask + 0); 19558c2ecf20Sopenharmony_ci uf.event_mask[1] &= *((u32 *) hci_sec_filter.event_mask + 1); 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci { 19598c2ecf20Sopenharmony_ci struct hci_filter *f = &hci_pi(sk)->filter; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci f->type_mask = uf.type_mask; 19628c2ecf20Sopenharmony_ci f->opcode = uf.opcode; 19638c2ecf20Sopenharmony_ci *((u32 *) f->event_mask + 0) = uf.event_mask[0]; 19648c2ecf20Sopenharmony_ci *((u32 *) f->event_mask + 1) = uf.event_mask[1]; 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci break; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci default: 19698c2ecf20Sopenharmony_ci err = -ENOPROTOOPT; 19708c2ecf20Sopenharmony_ci break; 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_cidone: 19748c2ecf20Sopenharmony_ci release_sock(sk); 19758c2ecf20Sopenharmony_ci return err; 19768c2ecf20Sopenharmony_ci} 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_cistatic int hci_sock_getsockopt(struct socket *sock, int level, int optname, 19798c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 19808c2ecf20Sopenharmony_ci{ 19818c2ecf20Sopenharmony_ci struct hci_ufilter uf; 19828c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 19838c2ecf20Sopenharmony_ci int len, opt, err = 0; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci BT_DBG("sk %p, opt %d", sk, optname); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci if (level != SOL_HCI) 19888c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci if (get_user(len, optlen)) 19918c2ecf20Sopenharmony_ci return -EFAULT; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci lock_sock(sk); 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { 19968c2ecf20Sopenharmony_ci err = -EBADFD; 19978c2ecf20Sopenharmony_ci goto done; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci switch (optname) { 20018c2ecf20Sopenharmony_ci case HCI_DATA_DIR: 20028c2ecf20Sopenharmony_ci if (hci_pi(sk)->cmsg_mask & HCI_CMSG_DIR) 20038c2ecf20Sopenharmony_ci opt = 1; 20048c2ecf20Sopenharmony_ci else 20058c2ecf20Sopenharmony_ci opt = 0; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci if (put_user(opt, optval)) 20088c2ecf20Sopenharmony_ci err = -EFAULT; 20098c2ecf20Sopenharmony_ci break; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci case HCI_TIME_STAMP: 20128c2ecf20Sopenharmony_ci if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP) 20138c2ecf20Sopenharmony_ci opt = 1; 20148c2ecf20Sopenharmony_ci else 20158c2ecf20Sopenharmony_ci opt = 0; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci if (put_user(opt, optval)) 20188c2ecf20Sopenharmony_ci err = -EFAULT; 20198c2ecf20Sopenharmony_ci break; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci case HCI_FILTER: 20228c2ecf20Sopenharmony_ci { 20238c2ecf20Sopenharmony_ci struct hci_filter *f = &hci_pi(sk)->filter; 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci memset(&uf, 0, sizeof(uf)); 20268c2ecf20Sopenharmony_ci uf.type_mask = f->type_mask; 20278c2ecf20Sopenharmony_ci uf.opcode = f->opcode; 20288c2ecf20Sopenharmony_ci uf.event_mask[0] = *((u32 *) f->event_mask + 0); 20298c2ecf20Sopenharmony_ci uf.event_mask[1] = *((u32 *) f->event_mask + 1); 20308c2ecf20Sopenharmony_ci } 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci len = min_t(unsigned int, len, sizeof(uf)); 20338c2ecf20Sopenharmony_ci if (copy_to_user(optval, &uf, len)) 20348c2ecf20Sopenharmony_ci err = -EFAULT; 20358c2ecf20Sopenharmony_ci break; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci default: 20388c2ecf20Sopenharmony_ci err = -ENOPROTOOPT; 20398c2ecf20Sopenharmony_ci break; 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cidone: 20438c2ecf20Sopenharmony_ci release_sock(sk); 20448c2ecf20Sopenharmony_ci return err; 20458c2ecf20Sopenharmony_ci} 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_cistatic void hci_sock_destruct(struct sock *sk) 20488c2ecf20Sopenharmony_ci{ 20498c2ecf20Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 20508c2ecf20Sopenharmony_ci skb_queue_purge(&sk->sk_write_queue); 20518c2ecf20Sopenharmony_ci} 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_cistatic const struct proto_ops hci_sock_ops = { 20548c2ecf20Sopenharmony_ci .family = PF_BLUETOOTH, 20558c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 20568c2ecf20Sopenharmony_ci .release = hci_sock_release, 20578c2ecf20Sopenharmony_ci .bind = hci_sock_bind, 20588c2ecf20Sopenharmony_ci .getname = hci_sock_getname, 20598c2ecf20Sopenharmony_ci .sendmsg = hci_sock_sendmsg, 20608c2ecf20Sopenharmony_ci .recvmsg = hci_sock_recvmsg, 20618c2ecf20Sopenharmony_ci .ioctl = hci_sock_ioctl, 20628c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 20638c2ecf20Sopenharmony_ci .compat_ioctl = hci_sock_compat_ioctl, 20648c2ecf20Sopenharmony_ci#endif 20658c2ecf20Sopenharmony_ci .poll = datagram_poll, 20668c2ecf20Sopenharmony_ci .listen = sock_no_listen, 20678c2ecf20Sopenharmony_ci .shutdown = sock_no_shutdown, 20688c2ecf20Sopenharmony_ci .setsockopt = hci_sock_setsockopt, 20698c2ecf20Sopenharmony_ci .getsockopt = hci_sock_getsockopt, 20708c2ecf20Sopenharmony_ci .connect = sock_no_connect, 20718c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 20728c2ecf20Sopenharmony_ci .accept = sock_no_accept, 20738c2ecf20Sopenharmony_ci .mmap = sock_no_mmap 20748c2ecf20Sopenharmony_ci}; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_cistatic struct proto hci_sk_proto = { 20778c2ecf20Sopenharmony_ci .name = "HCI", 20788c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 20798c2ecf20Sopenharmony_ci .obj_size = sizeof(struct hci_pinfo) 20808c2ecf20Sopenharmony_ci}; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_cistatic int hci_sock_create(struct net *net, struct socket *sock, int protocol, 20838c2ecf20Sopenharmony_ci int kern) 20848c2ecf20Sopenharmony_ci{ 20858c2ecf20Sopenharmony_ci struct sock *sk; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci BT_DBG("sock %p", sock); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci if (sock->type != SOCK_RAW) 20908c2ecf20Sopenharmony_ci return -ESOCKTNOSUPPORT; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci sock->ops = &hci_sock_ops; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, kern); 20958c2ecf20Sopenharmony_ci if (!sk) 20968c2ecf20Sopenharmony_ci return -ENOMEM; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci sock_init_data(sock, sk); 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci sock_reset_flag(sk, SOCK_ZAPPED); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci sk->sk_protocol = protocol; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 21058c2ecf20Sopenharmony_ci sk->sk_state = BT_OPEN; 21068c2ecf20Sopenharmony_ci sk->sk_destruct = hci_sock_destruct; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci bt_sock_link(&hci_sk_list, sk); 21098c2ecf20Sopenharmony_ci return 0; 21108c2ecf20Sopenharmony_ci} 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_cistatic const struct net_proto_family hci_sock_family_ops = { 21138c2ecf20Sopenharmony_ci .family = PF_BLUETOOTH, 21148c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 21158c2ecf20Sopenharmony_ci .create = hci_sock_create, 21168c2ecf20Sopenharmony_ci}; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ciint __init hci_sock_init(void) 21198c2ecf20Sopenharmony_ci{ 21208c2ecf20Sopenharmony_ci int err; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct sockaddr_hci) > sizeof(struct sockaddr)); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci err = proto_register(&hci_sk_proto, 0); 21258c2ecf20Sopenharmony_ci if (err < 0) 21268c2ecf20Sopenharmony_ci return err; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci err = bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops); 21298c2ecf20Sopenharmony_ci if (err < 0) { 21308c2ecf20Sopenharmony_ci BT_ERR("HCI socket registration failed"); 21318c2ecf20Sopenharmony_ci goto error; 21328c2ecf20Sopenharmony_ci } 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci err = bt_procfs_init(&init_net, "hci", &hci_sk_list, NULL); 21358c2ecf20Sopenharmony_ci if (err < 0) { 21368c2ecf20Sopenharmony_ci BT_ERR("Failed to create HCI proc file"); 21378c2ecf20Sopenharmony_ci bt_sock_unregister(BTPROTO_HCI); 21388c2ecf20Sopenharmony_ci goto error; 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci BT_INFO("HCI socket layer initialized"); 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci return 0; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_cierror: 21468c2ecf20Sopenharmony_ci proto_unregister(&hci_sk_proto); 21478c2ecf20Sopenharmony_ci return err; 21488c2ecf20Sopenharmony_ci} 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_civoid hci_sock_cleanup(void) 21518c2ecf20Sopenharmony_ci{ 21528c2ecf20Sopenharmony_ci bt_procfs_cleanup(&init_net, "hci"); 21538c2ecf20Sopenharmony_ci bt_sock_unregister(BTPROTO_HCI); 21548c2ecf20Sopenharmony_ci proto_unregister(&hci_sk_proto); 21558c2ecf20Sopenharmony_ci} 2156