18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020 Google Corporation 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 78c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "msft.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define MSFT_OP_READ_SUPPORTED_FEATURES 0x00 128c2ecf20Sopenharmony_cistruct msft_cp_read_supported_features { 138c2ecf20Sopenharmony_ci __u8 sub_opcode; 148c2ecf20Sopenharmony_ci} __packed; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistruct msft_rp_read_supported_features { 178c2ecf20Sopenharmony_ci __u8 status; 188c2ecf20Sopenharmony_ci __u8 sub_opcode; 198c2ecf20Sopenharmony_ci __le64 features; 208c2ecf20Sopenharmony_ci __u8 evt_prefix_len; 218c2ecf20Sopenharmony_ci __u8 evt_prefix[]; 228c2ecf20Sopenharmony_ci} __packed; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct msft_data { 258c2ecf20Sopenharmony_ci __u64 features; 268c2ecf20Sopenharmony_ci __u8 evt_prefix_len; 278c2ecf20Sopenharmony_ci __u8 *evt_prefix; 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic bool read_supported_features(struct hci_dev *hdev, 318c2ecf20Sopenharmony_ci struct msft_data *msft) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct msft_cp_read_supported_features cp; 348c2ecf20Sopenharmony_ci struct msft_rp_read_supported_features *rp; 358c2ecf20Sopenharmony_ci struct sk_buff *skb; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci cp.sub_opcode = MSFT_OP_READ_SUPPORTED_FEATURES; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp, 408c2ecf20Sopenharmony_ci HCI_CMD_TIMEOUT); 418c2ecf20Sopenharmony_ci if (IS_ERR(skb)) { 428c2ecf20Sopenharmony_ci bt_dev_err(hdev, "Failed to read MSFT supported features (%ld)", 438c2ecf20Sopenharmony_ci PTR_ERR(skb)); 448c2ecf20Sopenharmony_ci return false; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (skb->len < sizeof(*rp)) { 488c2ecf20Sopenharmony_ci bt_dev_err(hdev, "MSFT supported features length mismatch"); 498c2ecf20Sopenharmony_ci goto failed; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci rp = (struct msft_rp_read_supported_features *)skb->data; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (rp->sub_opcode != MSFT_OP_READ_SUPPORTED_FEATURES) 558c2ecf20Sopenharmony_ci goto failed; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (rp->evt_prefix_len > 0) { 588c2ecf20Sopenharmony_ci msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len, 598c2ecf20Sopenharmony_ci GFP_KERNEL); 608c2ecf20Sopenharmony_ci if (!msft->evt_prefix) 618c2ecf20Sopenharmony_ci goto failed; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci msft->evt_prefix_len = rp->evt_prefix_len; 658c2ecf20Sopenharmony_ci msft->features = __le64_to_cpu(rp->features); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci kfree_skb(skb); 688c2ecf20Sopenharmony_ci return true; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cifailed: 718c2ecf20Sopenharmony_ci kfree_skb(skb); 728c2ecf20Sopenharmony_ci return false; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_civoid msft_do_open(struct hci_dev *hdev) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct msft_data *msft; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (hdev->msft_opcode == HCI_OP_NOP) 808c2ecf20Sopenharmony_ci return; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci bt_dev_dbg(hdev, "Initialize MSFT extension"); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci msft = kzalloc(sizeof(*msft), GFP_KERNEL); 858c2ecf20Sopenharmony_ci if (!msft) 868c2ecf20Sopenharmony_ci return; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (!read_supported_features(hdev, msft)) { 898c2ecf20Sopenharmony_ci kfree(msft); 908c2ecf20Sopenharmony_ci return; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci hdev->msft_data = msft; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_civoid msft_do_close(struct hci_dev *hdev) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct msft_data *msft = hdev->msft_data; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (!msft) 1018c2ecf20Sopenharmony_ci return; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci bt_dev_dbg(hdev, "Cleanup of MSFT extension"); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci hdev->msft_data = NULL; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci kfree(msft->evt_prefix); 1088c2ecf20Sopenharmony_ci kfree(msft); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_civoid msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct msft_data *msft = hdev->msft_data; 1148c2ecf20Sopenharmony_ci u8 event; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (!msft) 1178c2ecf20Sopenharmony_ci return; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* When the extension has defined an event prefix, check that it 1208c2ecf20Sopenharmony_ci * matches, and otherwise just return. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci if (msft->evt_prefix_len > 0) { 1238c2ecf20Sopenharmony_ci if (skb->len < msft->evt_prefix_len) 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (memcmp(skb->data, msft->evt_prefix, msft->evt_prefix_len)) 1278c2ecf20Sopenharmony_ci return; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci skb_pull(skb, msft->evt_prefix_len); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Every event starts at least with an event code and the rest of 1338c2ecf20Sopenharmony_ci * the data is variable and depends on the event code. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci if (skb->len < 1) 1368c2ecf20Sopenharmony_ci return; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci event = *skb->data; 1398c2ecf20Sopenharmony_ci skb_pull(skb, 1); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci bt_dev_dbg(hdev, "MSFT vendor event %u", event); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci__u64 msft_get_features(struct hci_dev *hdev) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct msft_data *msft = hdev->msft_data; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return msft ? msft->features : 0; 1498c2ecf20Sopenharmony_ci} 150