15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* 25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * QEMU Bluetooth HCI logic. 35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (C) 2007 OpenMoko, Inc. 55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (C) 2008 Andrzej Zaborowski <balrog@zabor.org> 65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This program is free software; you can redistribute it and/or 85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * modify it under the terms of the GNU General Public License as 95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * published by the Free Software Foundation; either version 2 of 105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the License, or (at your option) any later version. 115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This program is distributed in the hope that it will be useful, 135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * but WITHOUT ANY WARRANTY; without even the implied warranty of 145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * GNU General Public License for more details. 165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * You should have received a copy of the GNU General Public License 18a7fb77d6eca56e61e94f62e7deb4120b60b1e919David 'Digit' Turner * along with this program; if not, see <http://www.gnu.org/licenses/>. 195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h" 225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-timer.h" 235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "usb.h" 245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "net.h" 255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "bt.h" 265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct bt_hci_s { 285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t *(*evt_packet)(void *opaque); 295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void (*evt_submit)(void *opaque, int len); 305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *opaque; 315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t evt_buf[256]; 325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t acl_buf[4096]; 345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int acl_len; 355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t asb_handle; 375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t psb_handle; 385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int last_cmd; /* Note: Always little-endian */ 405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *conn_req_host; 425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct { 445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int inquire; 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int periodic; 465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int responses_left; 475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int responses; 485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUTimer *inquiry_done; 495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUTimer *inquiry_next; 505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int inquiry_length; 515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int inquiry_period; 525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int inquiry_mode; 535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define HCI_HANDLE_OFFSET 0x20 555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define HCI_HANDLES_MAX 0x10 565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_master_link_s { 575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_link_s *link; 585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void (*lmp_acl_data)(struct bt_link_s *link, 595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const uint8_t *data, int start, int len); 605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUTimer *acl_mode_timer; 615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } handle[HCI_HANDLES_MAX]; 625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint32_t role_bmp; 635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int last_handle; 645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int connecting; 655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdaddr_t awaiting_bdaddr[HCI_HANDLES_MAX]; 665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } lm; 675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t event_mask[8]; 695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t voice_setting; /* Notw: Always little-endian */ 705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t conn_accept_tout; 715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner QEMUTimer *conn_accept_timer; 725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct HCIInfo info; 745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s device; 755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}; 765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define DEFAULT_RSSI_DBM 20 785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define hci_from_info(ptr) container_of((ptr), struct bt_hci_s, info) 805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define hci_from_device(ptr) container_of((ptr), struct bt_hci_s, device) 815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct bt_hci_link_s { 835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_link_s btlink; 845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle; /* Local */ 855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}; 865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* LMP layer emulation */ 885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if 0 895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_submit_lmp(struct bt_device_s *bt, int length, uint8_t *data) 905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int resp, resplen, error, op, tr; 925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t respdata[17]; 935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 1) 955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner tr = *data & 1; 985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner op = *(data ++) >> 1; 995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_ACCEPTED; 1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 2; 1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[1] = op; 1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = 0; 1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner length --; 1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (op >= 0x7c) { /* Extended opcode */ 1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner op |= *(data ++) << 8; 1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_ACCEPTED_EXT; 1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 4; 1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[0] = op >> 8; 1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[1] = op & 0xff; 1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner length --; 1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (op) { 1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_ACCEPTED: 1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0] Op code 1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 1) { 1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_ACCEPTED_EXT: 1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0] Escape op code 1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * data[1] Extended op code 1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 2) { 1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_NOT_ACCEPTED: 1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0] Op code 1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * data[1] Error code 1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 2) { 1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_NOT_ACCEPTED_EXT: 1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0] Op code 1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * data[1] Extended op code 1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * data[2] Error code 1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 3) { 1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_HOST_CONNECTION_REQ: 1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_SETUP_COMPLETE: 1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_SETUP_COMPLETE; 1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 1; 1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt->setup = 1; 1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_DETACH: 1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0] Error code 1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 1) { 1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt->setup = 0; 1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_SUPERVISION_TIMEOUT: 1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0,1] Supervision timeout 1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 2) { 1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_QUALITY_OF_SERVICE: 1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Fall through */ 1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_QOS_REQ: 1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0,1] Poll interval 1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * data[2] N(BC) 1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 3) { 1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_MAX_SLOT: 2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Fall through */ 2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_MAX_SLOT_REQ: 2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0] Max slots 2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 1) { 2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_AU_RAND: 2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_IN_RAND: 2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_COMB_KEY: 2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0-15] Random number 2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 16) { 2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (op == LMP_AU_RAND) { 2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt->key_present) { 2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_SRES; 2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 5; 2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* XXX: [Part H] Section 6.1 on page 801 */ 2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_PIN_OR_KEY_MISSING; 2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else if (op == LMP_IN_RAND) { 2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_PAIRING_NOT_ALLOWED; 2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* XXX: [Part H] Section 3.2 on page 779 */ 2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_UNIT_KEY; 2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 17; 2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(respdata + 1, bt->key, 16); 2405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNIT_LINK_KEY_USED; 2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_UNIT_KEY: 2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0-15] Key 2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 16) { 2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(bt->key, data, 16); 2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt->key_present = 1; 2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_SRES: 2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0-3] Authentication response 2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 4) { 2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_CLKOFFSET_REQ: 2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_CLKOFFSET_RES; 2685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 3; 2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[1] = 0x33; 2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[2] = 0x33; 2715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_CLKOFFSET_RES: 2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0,1] Clock offset 2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * (Slave to master only) 2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 2) { 2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_VERSION_REQ: 2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_VERSION_RES: 2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0] VersNr 2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * data[1,2] CompId 2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * data[3,4] SubVersNr 2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 5) { 2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (op == LMP_VERSION_REQ) { 2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_VERSION_RES; 2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 6; 2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[1] = 0x20; 2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[2] = 0xff; 2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[3] = 0xff; 2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[4] = 0xff; 3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[5] = 0xff; 3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else 3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_FEATURES_REQ: 3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_FEATURES_RES: 3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0-7] Features 3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 8) { 3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (op == LMP_FEATURES_REQ) { 3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_FEATURES_RES; 3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 9; 3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[1] = (bt->lmp_caps >> 0) & 0xff; 3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[2] = (bt->lmp_caps >> 8) & 0xff; 3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[3] = (bt->lmp_caps >> 16) & 0xff; 3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[4] = (bt->lmp_caps >> 24) & 0xff; 3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[5] = (bt->lmp_caps >> 32) & 0xff; 3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[6] = (bt->lmp_caps >> 40) & 0xff; 3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[7] = (bt->lmp_caps >> 48) & 0xff; 3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[8] = (bt->lmp_caps >> 56) & 0xff; 3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else 3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_NAME_REQ: 3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0] Name offset 3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 1) { 3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_NAME_RES; 3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 17; 3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[1] = data[0]; 3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[2] = strlen(bt->lmp_name); 3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(respdata + 3, 0x00, 14); 3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (respdata[2] > respdata[1]) 3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(respdata + 3, bt->lmp_name + respdata[1], 3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[2] - respdata[1]); 3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 3445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LMP_NAME_RES: 3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* data[0] Name offset 3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * data[1] Name length 3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * data[2-15] Name fragment 3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */ 3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 16) { 3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE; 3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto not_accepted; 3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = 0; 3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner error = HCI_UNKNOWN_LMP_PDU; 3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Fall through */ 3605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner not_accepted: 3615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (op >> 8) { 3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_NOT_ACCEPTED_EXT; 3635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 5; 3645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[0] = op >> 8; 3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[1] = op & 0xff; 3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[2] = error; 3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resp = LMP_NOT_ACCEPTED; 3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner resplen = 3; 3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[0] = op & 0xff; 3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[1] = error; 3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (resp == 0) 3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (resp >> 8) { 3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[0] = resp >> 8; 3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[1] = resp & 0xff; 3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else 3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[0] = resp & 0xff; 3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[0] <<= 1; 3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner respdata[0] |= tr; 3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_submit_raw_acl(struct bt_piconet_s *net, int length, uint8_t *data) 3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *slave; 3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 1) 3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner slave = 0; 3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if 0 3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner slave = net->slave; 3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (data[0] & 3) { 4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LLID_ACLC: 4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_submit_lmp(slave, length - 1, data + 1); 4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LLID_ACLU_START: 4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if 0 4055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_sumbit_l2cap(slave, length - 1, data + 1, (data[0] >> 2) & 1); 4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner breka; 4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case LLID_ACLU_CONT: 4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 4145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* HCI layer emulation */ 4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Note: we could ignore endiannes because unswapped handles will still 4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * be valid as connection identifiers for the guest - they don't have to 4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * be continuously allocated. We do it though, to preserve similar 4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * behaviour between hosts. Some things, like the BD_ADDR cannot be 4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * preserved though (for example if a real hci is used). */ 42220894ae3fa98f82da925fbeb72e616eef509758aDavid 'Digit' Turner#ifdef HOST_WORDS_BIGENDIAN 4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner# define HNDL(raw) bswap16(raw) 4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else 4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner# define HNDL(raw) (raw) 4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif 4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const uint8_t bt_event_reserved_mask[8] = { 4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 0xff, 0x9f, 0xfb, 0xff, 0x07, 0x18, 0x00, 0x00, 4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}; 4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci, 4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int evt, int len) 4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t *packet, mask; 4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int mask_byte; 4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len > 255) { 4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: HCI event params too long (%ib)\n", 4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__, len); 4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(-1); 4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner mask_byte = (evt - 1) >> 3; 4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner mask = 1 << ((evt - 1) & 3); 4465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (mask & bt_event_reserved_mask[mask_byte] & ~hci->event_mask[mask_byte]) 4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return NULL; 4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner packet = hci->evt_packet(hci->opaque); 4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner packet[0] = evt; 4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner packet[1] = len; 4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return &packet[2]; 4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event(struct bt_hci_s *hci, int evt, 4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *params, int len) 4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t *packet = bt_hci_event_start(hci, evt, len); 4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!packet) 4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len) 4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(packet, params, len); 4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->evt_submit(hci->opaque, len + 2); 4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_status(struct bt_hci_s *hci, int status) 4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_cmd_status params = { 4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = status, 4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .ncmd = 1, 4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .opcode = hci->last_cmd, 4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_CMD_STATUS, ¶ms, EVT_CMD_STATUS_SIZE); 4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete(struct bt_hci_s *hci, 4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner void *ret, int len) 4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE, 4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len + EVT_CMD_COMPLETE_SIZE); 4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_cmd_complete *params = (evt_cmd_complete *) packet; 4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!packet) 4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params->ncmd = 1; 4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params->opcode = hci->last_cmd; 4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len) 4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(&packet[EVT_CMD_COMPLETE_SIZE], ret, len); 4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->evt_submit(hci->opaque, len + EVT_CMD_COMPLETE_SIZE + 2); 4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_inquiry_done(void *opaque) 5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = (struct bt_hci_s *) opaque; 5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t status = HCI_SUCCESS; 5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!hci->lm.periodic) 5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.inquire = 0; 5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* The specification is inconsistent about this one. Page 565 reads 5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * "The event parameters of Inquiry Complete event will have a summary 5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * of the result from the Inquiry process, which reports the number of 5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * nearby Bluetooth devices that responded [so hci->responses].", but 5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Event Parameters (see page 729) has only Status. */ 5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_INQUIRY_COMPLETE, &status, 1); 5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_inquiry_result_standard(struct bt_hci_s *hci, 5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *slave) 5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner inquiry_info params = { 5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .num_responses = 1, 5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .bdaddr = BAINIT(&slave->bd_addr), 5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .pscan_rep_mode = 0x00, /* R0 */ 5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .pscan_period_mode = 0x00, /* P0 - deprecated */ 5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .pscan_mode = 0x00, /* Standard scan - deprecated */ 5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .dev_class[0] = slave->class[0], 5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .dev_class[1] = slave->class[1], 5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .dev_class[2] = slave->class[2], 5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: return the clkoff *differenece* */ 5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .clock_offset = slave->clkoff, /* Note: no swapping */ 5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_INQUIRY_RESULT, ¶ms, INQUIRY_INFO_SIZE); 5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_inquiry_result_with_rssi(struct bt_hci_s *hci, 5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *slave) 5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner inquiry_info_with_rssi params = { 5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .num_responses = 1, 5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .bdaddr = BAINIT(&slave->bd_addr), 5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .pscan_rep_mode = 0x00, /* R0 */ 5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .pscan_period_mode = 0x00, /* P0 - deprecated */ 5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .dev_class[0] = slave->class[0], 5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .dev_class[1] = slave->class[1], 5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .dev_class[2] = slave->class[2], 5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: return the clkoff *differenece* */ 5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .clock_offset = slave->clkoff, /* Note: no swapping */ 5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .rssi = DEFAULT_RSSI_DBM, 5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_INQUIRY_RESULT_WITH_RSSI, 5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ¶ms, INQUIRY_INFO_WITH_RSSI_SIZE); 5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_inquiry_result(struct bt_hci_s *hci, 5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *slave) 5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!slave->inquiry_scan || !hci->lm.responses_left) 5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.responses_left --; 5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.responses ++; 5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (hci->lm.inquiry_mode) { 5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x00: 5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_inquiry_result_standard(hci, slave); 5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case 0x01: 5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_inquiry_result_with_rssi(hci, slave); 5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: bad inquiry mode %02x\n", __FUNCTION__, 5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.inquiry_mode); 5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner exit(-1); 5745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 5755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period) 5785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5795973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner qemu_mod_timer(timer, qemu_get_clock_ns(vm_clock) + 580a7fb77d6eca56e61e94f62e7deb4120b60b1e919David 'Digit' Turner muldiv64(period << 7, get_ticks_per_sec(), 100)); 5815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 5825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_inquiry_start(struct bt_hci_s *hci, int length) 5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *slave; 5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.inquiry_length = length; 5885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (slave = hci->device.net->slave; slave; slave = slave->next) 5895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Don't uncover ourselves. */ 5905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (slave != &hci->device) 5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_inquiry_result(hci, slave); 5925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 5935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: register for a callback on a new device's addition to the 5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * scatternet so that if it's added before inquiry_length expires, 5955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * an Inquiry Result is generated immediately. Alternatively re-loop 5965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * through the devices on the inquiry_length expiration and report 5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * devices not seen before. */ 5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hci->lm.responses_left) 5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_mod_timer_1280ms(hci->lm.inquiry_done, hci->lm.inquiry_length); 6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_inquiry_done(hci); 6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hci->lm.periodic) 6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_mod_timer_1280ms(hci->lm.inquiry_next, hci->lm.inquiry_period); 6055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_inquiry_next(void *opaque) 6085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = (struct bt_hci_s *) opaque; 6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.responses_left += hci->lm.responses; 6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.responses = 0; 6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_inquiry_start(hci, hci->lm.inquiry_length); 6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int bt_hci_handle_bad(struct bt_hci_s *hci, uint16_t handle) 6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return !(handle & HCI_HANDLE_OFFSET) || 6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner handle >= (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX) || 6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner !hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link; 6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int bt_hci_role_master(struct bt_hci_s *hci, uint16_t handle) 6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return !!(hci->lm.role_bmp & (1 << (handle & ~HCI_HANDLE_OFFSET))); 6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline struct bt_device_s *bt_hci_remote_dev(struct bt_hci_s *hci, 6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle) 6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_link_s *link = hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link; 6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return bt_hci_role_master(hci, handle) ? link->slave : link->host; 6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_mode_tick(void *opaque); 6375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_lmp_link_establish(struct bt_hci_s *hci, 6385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_link_s *link, int master) 6395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.handle[hci->lm.last_handle].link = link; 6415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (master) { 6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* We are the master side of an ACL link */ 6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.role_bmp |= 1 << hci->lm.last_handle; 6455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.handle[hci->lm.last_handle].lmp_acl_data = 6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->slave->lmp_acl_data; 6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else { 6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* We are the slave side of an ACL link */ 6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.role_bmp &= ~(1 << hci->lm.last_handle); 6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.handle[hci->lm.last_handle].lmp_acl_data = 6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->host->lmp_acl_resp; 6545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 6555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Mode */ 6575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (master) { 6585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->acl_mode = acl_active; 6595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.handle[hci->lm.last_handle].acl_mode_timer = 6605973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner qemu_new_timer_ns(vm_clock, bt_hci_mode_tick, link); 6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 6625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_lmp_link_teardown(struct bt_hci_s *hci, uint16_t handle) 6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner handle &= ~HCI_HANDLE_OFFSET; 6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.handle[handle].link = NULL; 6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_role_master(hci, handle)) { 6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(hci->lm.handle[handle].acl_mode_timer); 6715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free_timer(hci->lm.handle[handle].acl_mode_timer); 6725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 6735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_hci_connect(struct bt_hci_s *hci, bdaddr_t *bdaddr) 6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *slave; 6785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_link_s link; 6795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (slave = hci->device.net->slave; slave; slave = slave->next) 6815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr)) 6825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 6835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!slave || slave == &hci->device) 6845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENODEV; 6855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bacpy(&hci->lm.awaiting_bdaddr[hci->lm.connecting ++], &slave->bd_addr); 6875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link.slave = slave; 6895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link.host = &hci->device; 6905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link.slave->lmp_connection_request(&link); /* Always last */ 6915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 6935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 6945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 6955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_connection_reject(struct bt_hci_s *hci, 6965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *host, uint8_t because) 6975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 6985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_link_s link = { 6995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .slave = &hci->device, 7005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .host = host, 7015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Rest uninitialised */ 7025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 7035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner host->reject_reason = because; 7055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner host->lmp_connection_complete(&link); 7065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_connection_reject_event(struct bt_hci_s *hci, 7095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdaddr_t *bdaddr) 7105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 7115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_conn_complete params; 7125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = HCI_NO_CONNECTION; 7145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.handle = 0; 7155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bacpy(¶ms.bdaddr, bdaddr); 7165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.link_type = ACL_LINK; 7175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.encr_mode = 0x00; /* Encryption not required */ 7185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_CONN_COMPLETE, ¶ms, EVT_CONN_COMPLETE_SIZE); 7195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_connection_accept(struct bt_hci_s *hci, 7225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *host) 7235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_link_s *link = qemu_mallocz(sizeof(struct bt_hci_link_s)); 7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_conn_complete params; 7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle; 7275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t status = HCI_SUCCESS; 7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int tries = HCI_HANDLES_MAX; 7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Make a connection handle */ 7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries) 7335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.last_handle &= HCI_HANDLES_MAX - 1; 7345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner handle = hci->lm.last_handle | HCI_HANDLE_OFFSET; 7355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while ((handle == hci->asb_handle || handle == hci->psb_handle) && 7365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner tries); 7375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!tries) { 7395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(link); 7405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_connection_reject(hci, host, HCI_REJECTED_LIMITED_RESOURCES); 7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner status = HCI_NO_CONNECTION; 7425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto complete; 7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->btlink.slave = &hci->device; 7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->btlink.host = host; 7475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->handle = handle; 7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Link established */ 7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_lmp_link_establish(hci, &link->btlink, 0); 7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnercomplete: 7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = status; 7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.handle = HNDL(handle); 7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bacpy(¶ms.bdaddr, &host->bd_addr); 7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.link_type = ACL_LINK; 7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.encr_mode = 0x00; /* Encryption not required */ 7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_CONN_COMPLETE, ¶ms, EVT_CONN_COMPLETE_SIZE); 7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Neets to be done at the very end because it can trigger a (nested) 7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * disconnected, in case the other and had cancelled the request 7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * locally. */ 7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (status == HCI_SUCCESS) { 7645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner host->reject_reason = 0; 7655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner host->lmp_connection_complete(&link->btlink); 7665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_lmp_connection_request(struct bt_link_s *link) 7705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 7715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_device(link->slave); 7725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_conn_request params; 7735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hci->conn_req_host) { 7755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_connection_reject(hci, link->host, 7765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner HCI_REJECTED_LIMITED_RESOURCES); 7775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 7785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 7795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->conn_req_host = link->host; 7805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: if masked and auto-accept, then auto-accept, 7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * if masked and not auto-accept, then auto-reject */ 7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: kick the hci->conn_accept_timer, timeout after 7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * hci->conn_accept_tout * 0.625 msec */ 7845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bacpy(¶ms.bdaddr, &link->host->bd_addr); 7865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(¶ms.dev_class, &link->host->class, sizeof(params.dev_class)); 7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.link_type = ACL_LINK; 7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_CONN_REQUEST, ¶ms, EVT_CONN_REQUEST_SIZE); 7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_conn_accept_timeout(void *opaque) 7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = (struct bt_hci_s *) opaque; 7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!hci->conn_req_host) 7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Already accepted or rejected. If the other end cancelled the 7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * connection request then we still have to reject or accept it 7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * and then we'll get a disconnect. */ 8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO */ 8035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Remove from the list of devices which we wanted to connect to and 8065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * are awaiting a response from. If the callback sees a response from 8075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * a device which is not on the list it will assume it's a connection 8085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * that's been cancelled by the host in the meantime and immediately 8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * try to detach the link and send a Connection Complete. */ 8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_hci_lmp_connection_ready(struct bt_hci_s *hci, 8115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdaddr_t *bdaddr) 8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int i; 8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (i = 0; i < hci->lm.connecting; i ++) 8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bacmp(&hci->lm.awaiting_bdaddr[i], bdaddr)) { 8175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (i < -- hci->lm.connecting) 8185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bacpy(&hci->lm.awaiting_bdaddr[i], 8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner &hci->lm.awaiting_bdaddr[hci->lm.connecting]); 8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 1; 8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_lmp_connection_complete(struct bt_link_s *link) 8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_device(link->host); 8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_conn_complete params; 8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle; 8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t status = HCI_SUCCESS; 8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int tries = HCI_HANDLES_MAX; 8335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_lmp_connection_ready(hci, &link->slave->bd_addr)) { 8355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!hci->device.reject_reason) 8365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->slave->lmp_disconnect_slave(link); 8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner handle = 0; 8385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner status = HCI_NO_CONNECTION; 8395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto complete; 8405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hci->device.reject_reason) { 8435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner handle = 0; 8445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner status = hci->device.reject_reason; 8455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto complete; 8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Make a connection handle */ 8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner do { 8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries) 8515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.last_handle &= HCI_HANDLES_MAX - 1; 8525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner handle = hci->lm.last_handle | HCI_HANDLE_OFFSET; 8535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } while ((handle == hci->asb_handle || handle == hci->psb_handle) && 8545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner tries); 8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!tries) { 8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->slave->lmp_disconnect_slave(link); 8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner status = HCI_NO_CONNECTION; 8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto complete; 8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Link established */ 8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->handle = handle; 8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_lmp_link_establish(hci, link, 1); 8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnercomplete: 8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = status; 8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.handle = HNDL(handle); 8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.link_type = ACL_LINK; 8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bacpy(¶ms.bdaddr, &link->slave->bd_addr); 8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.encr_mode = 0x00; /* Encryption not required */ 8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_CONN_COMPLETE, ¶ms, EVT_CONN_COMPLETE_SIZE); 8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_disconnect(struct bt_hci_s *hci, 8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle, int reason) 8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_link_s *btlink = 8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link; 8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_link_s *link; 8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_disconn_complete params; 8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_role_master(hci, handle)) { 8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner btlink->slave->reject_reason = reason; 8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner btlink->slave->lmp_disconnect_slave(btlink); 8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* The link pointer is invalid from now on */ 8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto complete; 8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner btlink->host->reject_reason = reason; 8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner btlink->host->lmp_disconnect_master(btlink); 8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* We are the slave, we get to clean this burden */ 8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link = (struct bt_hci_link_s *) btlink; 8965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(link); 8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnercomplete: 8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_lmp_link_teardown(hci, handle); 9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = HCI_SUCCESS; 9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.handle = HNDL(handle); 9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.reason = HCI_CONNECTION_TERMINATED; 9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_DISCONN_COMPLETE, 9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ¶ms, EVT_DISCONN_COMPLETE_SIZE); 9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* TODO: use only one function */ 9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_lmp_disconnect_host(struct bt_link_s *link) 9105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_device(link->host); 9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle = link->handle; 9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_disconn_complete params; 9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_lmp_link_teardown(hci, handle); 9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = HCI_SUCCESS; 9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.handle = HNDL(handle); 9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.reason = hci->device.reject_reason; 9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_DISCONN_COMPLETE, 9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ¶ms, EVT_DISCONN_COMPLETE_SIZE); 9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_lmp_disconnect_slave(struct bt_link_s *btlink) 9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; 9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_device(btlink->slave); 9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle = link->handle; 9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_disconn_complete params; 9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(link); 9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_lmp_link_teardown(hci, handle); 9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = HCI_SUCCESS; 9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.handle = HNDL(handle); 9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.reason = hci->device.reject_reason; 9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_DISCONN_COMPLETE, 9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ¶ms, EVT_DISCONN_COMPLETE_SIZE); 9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_hci_name_req(struct bt_hci_s *hci, bdaddr_t *bdaddr) 9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *slave; 9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_remote_name_req_complete params; 9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int len; 9475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (slave = hci->device.net->slave; slave; slave = slave->next) 9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr)) 9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!slave) 9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENODEV; 9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 9555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = HCI_SUCCESS; 9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bacpy(¶ms.bdaddr, &slave->bd_addr); 9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = snprintf(params.name, sizeof(params.name), 9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "%s", slave->lmp_name ?: ""); 9605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(params.name + len, 0, sizeof(params.name) - len); 9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_REMOTE_NAME_REQ_COMPLETE, 9625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ¶ms, EVT_REMOTE_NAME_REQ_COMPLETE_SIZE); 9635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 9655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_hci_features_req(struct bt_hci_s *hci, uint16_t handle) 9685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *slave; 9705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_read_remote_features_complete params; 9715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, handle)) 9735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENODEV; 9745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner slave = bt_hci_remote_dev(hci, handle); 9765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 9785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = HCI_SUCCESS; 9805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.handle = HNDL(handle); 9815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.features[0] = (slave->lmp_caps >> 0) & 0xff; 9825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.features[1] = (slave->lmp_caps >> 8) & 0xff; 9835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.features[2] = (slave->lmp_caps >> 16) & 0xff; 9845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.features[3] = (slave->lmp_caps >> 24) & 0xff; 9855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.features[4] = (slave->lmp_caps >> 32) & 0xff; 9865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.features[5] = (slave->lmp_caps >> 40) & 0xff; 9875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.features[6] = (slave->lmp_caps >> 48) & 0xff; 9885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.features[7] = (slave->lmp_caps >> 56) & 0xff; 9895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_READ_REMOTE_FEATURES_COMPLETE, 9905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ¶ms, EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE); 9915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 9935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 9945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_hci_version_req(struct bt_hci_s *hci, uint16_t handle) 9965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 9975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_read_remote_version_complete params; 9985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 9995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, handle)) 10005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENODEV; 10015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1002a25351325187eb8eff8b9b090acd8f2d7684c6ffDavid Turner bt_hci_remote_dev(hci, handle); 10035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 10055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = HCI_SUCCESS; 10075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.handle = HNDL(handle); 10085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.lmp_ver = 0x03; 10095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.manufacturer = cpu_to_le16(0xa000); 10105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.lmp_subver = cpu_to_le16(0xa607); 10115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_READ_REMOTE_VERSION_COMPLETE, 10125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ¶ms, EVT_READ_REMOTE_VERSION_COMPLETE_SIZE); 10135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 10155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_hci_clkoffset_req(struct bt_hci_s *hci, uint16_t handle) 10185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_device_s *slave; 10205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_read_clock_offset_complete params; 10215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, handle)) 10235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENODEV; 10245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner slave = bt_hci_remote_dev(hci, handle); 10265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 10285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = HCI_SUCCESS; 10305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.handle = HNDL(handle); 10315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: return the clkoff *differenece* */ 10325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.clock_offset = slave->clkoff; /* Note: no swapping */ 10335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_READ_CLOCK_OFFSET_COMPLETE, 10345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ¶ms, EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE); 10355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 10375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_event_mode(struct bt_hci_s *hci, struct bt_link_s *link, 10405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle) 10415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_mode_change params = { 10435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 10445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .handle = HNDL(handle), 10455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .mode = link->acl_mode, 10465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .interval = cpu_to_le16(link->acl_interval), 10475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_MODE_CHANGE, ¶ms, EVT_MODE_CHANGE_SIZE); 10505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_lmp_mode_change_master(struct bt_hci_s *hci, 10535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_link_s *link, int mode, uint16_t interval) 10545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->acl_mode = mode; 10565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->acl_interval = interval; 10575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_mode(hci, link, link->handle); 10595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->slave->lmp_mode_change(link); 10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_lmp_mode_change_slave(struct bt_link_s *btlink) 10645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; 10665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_device(btlink->slave); 10675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_mode(hci, btlink, link->handle); 10695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle, 10725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int interval, int mode) 10735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_master_link_s *link; 10755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle)) 10775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENODEV; 10785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET]; 10805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (link->link->acl_mode != acl_active) { 10815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED); 10825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 10835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 10845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 10865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10875973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner qemu_mod_timer(link->acl_mode_timer, qemu_get_clock_ns(vm_clock) + 1088a7fb77d6eca56e61e94f62e7deb4120b60b1e919David 'Digit' Turner muldiv64(interval * 625, get_ticks_per_sec(), 1000000)); 10895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_lmp_mode_change_master(hci, link->link, mode, interval); 10905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 10925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 10935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_hci_mode_cancel(struct bt_hci_s *hci, uint16_t handle, int mode) 10955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 10965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_master_link_s *link; 10975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 10985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle)) 10995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return -ENODEV; 11005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET]; 11025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (link->link->acl_mode != mode) { 11035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED); 11045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 11065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 11075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 11095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(link->acl_mode_timer); 11115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_lmp_mode_change_master(hci, link->link, acl_active, 0); 11125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 11145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 11155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_mode_tick(void *opaque) 11175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_link_s *link = opaque; 11195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_device(link->host); 11205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_lmp_mode_change_master(hci, link, acl_active, 0); 11225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 11235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_reset(struct bt_hci_s *hci) 11255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->acl_len = 0; 11275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->last_cmd = 0; 11285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.connecting = 0; 11295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->event_mask[0] = 0xff; 11315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->event_mask[1] = 0xff; 11325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->event_mask[2] = 0xff; 11335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->event_mask[3] = 0xff; 11345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->event_mask[4] = 0xff; 11355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->event_mask[5] = 0x1f; 11365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->event_mask[6] = 0x00; 11375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->event_mask[7] = 0x00; 11385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->device.inquiry_scan = 0; 11395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->device.page_scan = 0; 11405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hci->device.lmp_name) 11415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free((void *) hci->device.lmp_name); 11425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->device.lmp_name = NULL; 11435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->device.class[0] = 0x00; 11445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->device.class[1] = 0x00; 11455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->device.class[2] = 0x00; 11465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->voice_setting = 0x0000; 11475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->conn_accept_tout = 0x1f40; 11485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.inquiry_mode = 0x00; 11495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->psb_handle = 0x000; 11515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->asb_handle = 0x000; 11525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* XXX: qemu_del_timer(sl->acl_mode_timer); for all links */ 11545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(hci->lm.inquiry_done); 11555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(hci->lm.inquiry_next); 11565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(hci->conn_accept_timer); 11575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 11585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_read_local_version_rp(struct bt_hci_s *hci) 11605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_local_version_rp lv = { 11625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 11635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .hci_ver = 0x03, 11645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .hci_rev = cpu_to_le16(0xa607), 11655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .lmp_ver = 0x03, 11665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .manufacturer = cpu_to_le16(0xa000), 11675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .lmp_subver = cpu_to_le16(0xa607), 11685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 11695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, &lv, READ_LOCAL_VERSION_RP_SIZE); 11715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 11725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_read_local_commands_rp(struct bt_hci_s *hci) 11745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_local_commands_rp lc = { 11765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 11775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .commands = { 11785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Keep updated! */ 11795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Also, keep in sync with hci->device.lmp_caps in bt_new_hci */ 11805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 0xbf, 0x80, 0xf9, 0x03, 0xb2, 0xc0, 0x03, 0xc3, 11815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 0x00, 0x0f, 0x80, 0x00, 0xc0, 0x00, 0xe8, 0x13, 11825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 11835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 11845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 11855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 11865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 11875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 11885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }, 11895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 11905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, &lc, READ_LOCAL_COMMANDS_RP_SIZE); 11925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 11935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 11945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_read_local_features_rp(struct bt_hci_s *hci) 11955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 11965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_local_features_rp lf = { 11975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 11985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .features = { 11995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (hci->device.lmp_caps >> 0) & 0xff, 12005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (hci->device.lmp_caps >> 8) & 0xff, 12015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (hci->device.lmp_caps >> 16) & 0xff, 12025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (hci->device.lmp_caps >> 24) & 0xff, 12035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (hci->device.lmp_caps >> 32) & 0xff, 12045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (hci->device.lmp_caps >> 40) & 0xff, 12055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (hci->device.lmp_caps >> 48) & 0xff, 12065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (hci->device.lmp_caps >> 56) & 0xff, 12075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }, 12085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 12095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, &lf, READ_LOCAL_FEATURES_RP_SIZE); 12115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_read_local_ext_features_rp(struct bt_hci_s *hci, int page) 12145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_local_ext_features_rp lef = { 12165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 12175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .page_num = page, 12185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .max_page_num = 0x00, 12195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .features = { 12205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Keep updated! */ 12215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 0x5f, 0x35, 0x85, 0x7e, 0x9b, 0x19, 0x00, 0x80, 12225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }, 12235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 12245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (page) 12255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(lef.features, 0, sizeof(lef.features)); 12265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, &lef, READ_LOCAL_EXT_FEATURES_RP_SIZE); 12285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_read_buffer_size_rp(struct bt_hci_s *hci) 12315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_buffer_size_rp bs = { 12335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* This can be made configurable, for one standard USB dongle HCI 12345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the four values are cpu_to_le16(0x0180), 0x40, 12355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * cpu_to_le16(0x0008), cpu_to_le16(0x0008). */ 12365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 12375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .acl_mtu = cpu_to_le16(0x0200), 12385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .sco_mtu = 0, 12395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .acl_max_pkt = cpu_to_le16(0x0001), 12405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .sco_max_pkt = cpu_to_le16(0x0000), 12415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 12425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, &bs, READ_BUFFER_SIZE_RP_SIZE); 12445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Deprecated in V2.0 (page 661) */ 12475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_read_country_code_rp(struct bt_hci_s *hci) 12485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_country_code_rp cc ={ 12505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 12515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .country_code = 0x00, /* North America & Europe^1 and Japan */ 12525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 12535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, &cc, READ_COUNTRY_CODE_RP_SIZE); 12555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* ^1. Except France, sorry */ 12575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_read_bd_addr_rp(struct bt_hci_s *hci) 12605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_bd_addr_rp ba = { 12625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 12635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .bdaddr = BAINIT(&hci->device.bd_addr), 12645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 12655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, &ba, READ_BD_ADDR_RP_SIZE); 12675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_hci_link_quality_rp(struct bt_hci_s *hci, uint16_t handle) 12705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_link_quality_rp lq = { 12725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 12735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .handle = HNDL(handle), 12745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .link_quality = 0xff, 12755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 12765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, handle)) 12785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner lq.status = HCI_NO_CONNECTION; 12795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, &lq, READ_LINK_QUALITY_RP_SIZE); 12815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 12825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Generate a Command Complete event with only the Status parameter */ 12855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_status(struct bt_hci_s *hci, 12865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t status) 12875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, &status, 1); 12895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 12905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_conn_cancel(struct bt_hci_s *hci, 12925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint8_t status, bdaddr_t *bd_addr) 12935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 12945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner create_conn_cancel_rp params = { 12955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = status, 12965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .bdaddr = BAINIT(bd_addr), 12975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 12985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 12995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, CREATE_CONN_CANCEL_RP_SIZE); 13005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_auth_complete(struct bt_hci_s *hci, 13035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle) 13045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_auth_complete params = { 13065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 13075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .handle = HNDL(handle), 13085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 13095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_AUTH_COMPLETE, ¶ms, EVT_AUTH_COMPLETE_SIZE); 13115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_encrypt_change(struct bt_hci_s *hci, 13145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle, uint8_t mode) 13155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_encrypt_change params = { 13175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 13185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .handle = HNDL(handle), 13195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .encrypt = mode, 13205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 13215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_ENCRYPT_CHANGE, ¶ms, EVT_ENCRYPT_CHANGE_SIZE); 13235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_name_cancel(struct bt_hci_s *hci, 13265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bdaddr_t *bd_addr) 13275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner remote_name_req_cancel_rp params = { 13295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_INVALID_PARAMETERS, 13305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .bdaddr = BAINIT(bd_addr), 13315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 13325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, REMOTE_NAME_REQ_CANCEL_RP_SIZE); 13345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_read_remote_ext_features(struct bt_hci_s *hci, 13375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle) 13385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_read_remote_ext_features_complete params = { 13405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_UNSUPPORTED_FEATURE, 13415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .handle = HNDL(handle), 13425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Rest uninitialised */ 13435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 13445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE, 13465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ¶ms, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE); 13475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_lmp_handle(struct bt_hci_s *hci, 13505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle) 13515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_lmp_handle_rp params = { 13535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_NO_CONNECTION, 13545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .handle = HNDL(handle), 13555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .reserved = 0, 13565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Rest uninitialised */ 13575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 13585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, READ_LMP_HANDLE_RP_SIZE); 13605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_role_discovery(struct bt_hci_s *hci, 13635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int status, uint16_t handle, int master) 13645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner role_discovery_rp params = { 13665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = status, 13675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .handle = HNDL(handle), 13685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .role = master ? 0x00 : 0x01, 13695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 13705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, ROLE_DISCOVERY_RP_SIZE); 13725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_flush(struct bt_hci_s *hci, 13755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int status, uint16_t handle) 13765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner flush_rp params = { 13785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = status, 13795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .handle = HNDL(handle), 13805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 13815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, FLUSH_RP_SIZE); 13835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_read_local_name(struct bt_hci_s *hci) 13865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_local_name_rp params; 13885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = HCI_SUCCESS; 13895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memset(params.name, 0, sizeof(params.name)); 13905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hci->device.lmp_name) 13915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner strncpy(params.name, hci->device.lmp_name, sizeof(params.name)); 13925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, READ_LOCAL_NAME_RP_SIZE); 13945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 13955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 13965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_read_conn_accept_timeout( 13975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci) 13985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 13995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_conn_accept_timeout_rp params = { 14005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 14015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .timeout = cpu_to_le16(hci->conn_accept_tout), 14025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 14035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, READ_CONN_ACCEPT_TIMEOUT_RP_SIZE); 14055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_read_scan_enable(struct bt_hci_s *hci) 14085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_scan_enable_rp params = { 14105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 14115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .enable = 14125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (hci->device.inquiry_scan ? SCAN_INQUIRY : 0) | 14135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (hci->device.page_scan ? SCAN_PAGE : 0), 14145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 14155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, READ_SCAN_ENABLE_RP_SIZE); 14175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_read_local_class(struct bt_hci_s *hci) 14205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_class_of_dev_rp params; 14225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params.status = HCI_SUCCESS; 14245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(params.dev_class, hci->device.class, sizeof(params.dev_class)); 14255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, READ_CLASS_OF_DEV_RP_SIZE); 14275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_voice_setting(struct bt_hci_s *hci) 14305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_voice_setting_rp params = { 14325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 14335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .voice_setting = hci->voice_setting, /* Note: no swapping */ 14345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 14355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, READ_VOICE_SETTING_RP_SIZE); 14375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_complete_read_inquiry_mode( 14405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci) 14415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner read_inquiry_mode_rp params = { 14435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .status = HCI_SUCCESS, 14445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner .mode = hci->lm.inquiry_mode, 14455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner }; 14465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete(hci, ¶ms, READ_INQUIRY_MODE_RP_SIZE); 14485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci, 14515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle, int packets) 14525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t buf[EVT_NUM_COMP_PKTS_SIZE(1) / 2 + 1]; 14545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner evt_num_comp_pkts *params = (void *) ((uint8_t *) buf + 1); 14555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params->num_hndl = 1; 14575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params->connection->handle = HNDL(handle); 14585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner params->connection->num_packets = cpu_to_le16(packets); 14595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_NUM_COMP_PKTS, params, EVT_NUM_COMP_PKTS_SIZE(1)); 14615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 14625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_submit_hci(struct HCIInfo *info, 14645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const uint8_t *data, int length) 14655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 14665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_info(info); 14675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t cmd; 14685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int paramlen, i; 14695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < HCI_COMMAND_HDR_SIZE) 14715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto short_hci; 14725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(&hci->last_cmd, data, 2); 14745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner cmd = (data[1] << 8) | data[0]; 14765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner paramlen = data[2]; 14775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (cmd_opcode_ogf(cmd) == 0 || cmd_opcode_ocf(cmd) == 0) /* NOP */ 14785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 14795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner data += HCI_COMMAND_HDR_SIZE; 14815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner length -= HCI_COMMAND_HDR_SIZE; 14825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (paramlen > length) 14845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 14855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define PARAM(cmd, param) (((cmd##_cp *) data)->param) 14875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define PARAM16(cmd, param) le16_to_cpup(&PARAM(cmd, param)) 14885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define PARAMHANDLE(cmd) HNDL(PARAM(cmd, handle)) 14895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define LENGTH_CHECK(cmd) if (length < sizeof(cmd##_cp)) goto short_hci 14905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Note: the supported commands bitmask in bt_hci_read_local_commands_rp 14915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * needs to be updated every time a command is implemented here! */ 14925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner switch (cmd) { 14935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY): 14945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(inquiry); 14955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 14965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (PARAM(inquiry, length) < 1) { 14975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); 14985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 14995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.inquire = 1; 15025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.periodic = 0; 15035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.responses_left = PARAM(inquiry, num_rsp) ?: INT_MAX; 15045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.responses = 0; 15055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 15065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_inquiry_start(hci, PARAM(inquiry, length)); 15075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL): 15105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!hci->lm.inquire || hci->lm.periodic) { 15115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: Inquiry Cancel should only be issued after " 15125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "the Inquiry command has been issued, a Command " 15135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Status event has been received for the Inquiry " 15145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "command, and before the Inquiry Complete event " 15155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "occurs", __FUNCTION__); 15165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED); 15175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.inquire = 0; 15215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(hci->lm.inquiry_done); 15225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 15235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY): 15265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(periodic_inquiry); 15275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!(PARAM(periodic_inquiry, length) < 15295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(periodic_inquiry, min_period) && 15305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(periodic_inquiry, min_period) < 15315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(periodic_inquiry, max_period)) || 15325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM(periodic_inquiry, length) < 1 || 15335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(periodic_inquiry, min_period) < 2 || 15345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(periodic_inquiry, max_period) < 3) { 15355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); 15365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.inquire = 1; 15405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.periodic = 1; 15415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.responses_left = PARAM(periodic_inquiry, num_rsp); 15425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.responses = 0; 15435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.inquiry_period = PARAM16(periodic_inquiry, max_period); 15445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 15455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_inquiry_start(hci, PARAM(periodic_inquiry, length)); 15465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY): 15495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!hci->lm.inquire || !hci->lm.periodic) { 15505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: Inquiry Cancel should only be issued after " 15515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "the Inquiry command has been issued, a Command " 15525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "Status event has been received for the Inquiry " 15535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "command, and before the Inquiry Complete event " 15545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner "occurs", __FUNCTION__); 15555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED); 15565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.inquire = 0; 15595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(hci->lm.inquiry_done); 15605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_del_timer(hci->lm.inquiry_next); 15615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 15625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN): 15655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(create_conn); 15665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hci->lm.connecting >= HCI_HANDLES_MAX) { 15685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_REJECTED_LIMITED_RESOURCES); 15695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 15725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_connect(hci, &PARAM(create_conn, bdaddr))) 15745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_connection_reject_event(hci, &PARAM(create_conn, bdaddr)); 15755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_DISCONNECT): 15785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(disconnect); 15795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, PARAMHANDLE(disconnect))) { 15815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 15825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 15845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 15865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_disconnect(hci, PARAMHANDLE(disconnect), 15875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM(disconnect, reason)); 15885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 15895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN_CANCEL): 15915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(create_conn_cancel); 15925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 15935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_lmp_connection_ready(hci, 15945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner &PARAM(create_conn_cancel, bdaddr))) { 15955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (i = 0; i < HCI_HANDLES_MAX; i ++) 15965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_role_master(hci, i) && hci->lm.handle[i].link && 15975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner !bacmp(&hci->lm.handle[i].link->slave->bd_addr, 15985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner &PARAM(create_conn_cancel, bdaddr))) 15995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_conn_cancel(hci, i < HCI_HANDLES_MAX ? 16025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner HCI_ACL_CONNECTION_EXISTS : HCI_NO_CONNECTION, 16035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner &PARAM(create_conn_cancel, bdaddr)); 16045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } else 16055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_conn_cancel(hci, HCI_SUCCESS, 16065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner &PARAM(create_conn_cancel, bdaddr)); 16075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ): 16105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(accept_conn_req); 16115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!hci->conn_req_host || 16135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bacmp(&PARAM(accept_conn_req, bdaddr), 16145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner &hci->conn_req_host->bd_addr)) { 16155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); 16165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 16205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_connection_accept(hci, hci->conn_req_host); 16215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->conn_req_host = NULL; 16225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_REJECT_CONN_REQ): 16255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(reject_conn_req); 16265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!hci->conn_req_host || 16285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bacmp(&PARAM(reject_conn_req, bdaddr), 16295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner &hci->conn_req_host->bd_addr)) { 16305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); 16315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 16355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_connection_reject(hci, hci->conn_req_host, 16365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM(reject_conn_req, reason)); 16375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_connection_reject_event(hci, &hci->conn_req_host->bd_addr); 16385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->conn_req_host = NULL; 16395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_AUTH_REQUESTED): 16425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(auth_requested); 16435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, PARAMHANDLE(auth_requested))) 16455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 16465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else { 16475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 16485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_auth_complete(hci, PARAMHANDLE(auth_requested)); 16495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT): 16535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(set_conn_encrypt); 16545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, PARAMHANDLE(set_conn_encrypt))) 16565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 16575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else { 16585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 16595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_encrypt_change(hci, 16605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAMHANDLE(set_conn_encrypt), 16615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM(set_conn_encrypt, encrypt)); 16625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ): 16665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(remote_name_req); 16675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_name_req(hci, &PARAM(remote_name_req, bdaddr))) 16695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 16705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL): 16735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(remote_name_req_cancel); 16745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_name_cancel(hci, 16765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner &PARAM(remote_name_req_cancel, bdaddr)); 16775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_FEATURES): 16805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(read_remote_features); 16815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_features_req(hci, PARAMHANDLE(read_remote_features))) 16835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 16845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_EXT_FEATURES): 16875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(read_remote_ext_features); 16885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, PARAMHANDLE(read_remote_ext_features))) 16905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 16915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else { 16925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 16935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_read_remote_ext_features(hci, 16945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAMHANDLE(read_remote_ext_features)); 16955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 16965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 16975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 16985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_VERSION): 16995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(read_remote_version); 17005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_version_req(hci, PARAMHANDLE(read_remote_version))) 17025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 17035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_CLOCK_OFFSET): 17065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(read_clock_offset); 17075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_clkoffset_req(hci, PARAMHANDLE(read_clock_offset))) 17095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 17105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_LMP_HANDLE): 17135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(read_lmp_handle); 17145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: */ 17165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_lmp_handle(hci, PARAMHANDLE(read_lmp_handle)); 17175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_POLICY, OCF_HOLD_MODE): 17205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(hold_mode); 17215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (PARAM16(hold_mode, min_interval) > 17235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(hold_mode, max_interval) || 17245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(hold_mode, min_interval) < 0x0002 || 17255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(hold_mode, max_interval) > 0xff00 || 17265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (PARAM16(hold_mode, min_interval) & 1) || 17275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (PARAM16(hold_mode, max_interval) & 1)) { 17285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); 17295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_mode_change(hci, PARAMHANDLE(hold_mode), 17335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(hold_mode, max_interval), 17345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner acl_hold)) 17355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 17365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_POLICY, OCF_PARK_MODE): 17395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(park_mode); 17405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (PARAM16(park_mode, min_interval) > 17425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(park_mode, max_interval) || 17435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(park_mode, min_interval) < 0x000e || 17445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (PARAM16(park_mode, min_interval) & 1) || 17455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (PARAM16(park_mode, max_interval) & 1)) { 17465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); 17475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 17495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_mode_change(hci, PARAMHANDLE(park_mode), 17515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(park_mode, max_interval), 17525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner acl_parked)) 17535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 17545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_POLICY, OCF_EXIT_PARK_MODE): 17575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(exit_park_mode); 17585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_mode_cancel(hci, PARAMHANDLE(exit_park_mode), 17605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner acl_parked)) 17615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_NO_CONNECTION); 17625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_LINK_POLICY, OCF_ROLE_DISCOVERY): 17655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(role_discovery); 17665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, PARAMHANDLE(role_discovery))) 17685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_role_discovery(hci, 17695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner HCI_NO_CONNECTION, PARAMHANDLE(role_discovery), 0); 17705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 17715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_role_discovery(hci, 17725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner HCI_SUCCESS, PARAMHANDLE(role_discovery), 17735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_role_master(hci, 17745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAMHANDLE(role_discovery))); 17755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_MASK): 17785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(set_event_mask); 17795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(hci->event_mask, PARAM(set_event_mask, mask), 8); 17815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 17825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_RESET): 17855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_reset(hci); 17865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_SUCCESS); 17875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_FLT): 17905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length >= 1 && PARAM(set_event_flt, flt_type) == FLT_CLEAR_ALL) 17915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* No length check */; 17925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 17935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(set_event_flt); 17945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Filters are not implemented */ 17965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 17975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 17985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 17995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_FLUSH): 18005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(flush); 18015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, PARAMHANDLE(flush))) 18035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_flush(hci, 18045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner HCI_NO_CONNECTION, PARAMHANDLE(flush)); 18055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else { 18065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: ordering? */ 18075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event(hci, EVT_FLUSH_OCCURRED, 18085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner &PARAM(flush, handle), 18095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner EVT_FLUSH_OCCURRED_SIZE); 18105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_flush(hci, 18115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner HCI_SUCCESS, PARAMHANDLE(flush)); 18125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 18135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME): 18165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(change_local_name); 18175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hci->device.lmp_name) 18195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free((void *) hci->device.lmp_name); 18205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->device.lmp_name = qemu_strndup(PARAM(change_local_name, name), 18215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sizeof(PARAM(change_local_name, name))); 18225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 18235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME): 18265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_read_local_name(hci); 18275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CONN_ACCEPT_TIMEOUT): 18305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_read_conn_accept_timeout(hci); 18315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CONN_ACCEPT_TIMEOUT): 18345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO */ 18355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(write_conn_accept_timeout); 18365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (PARAM16(write_conn_accept_timeout, timeout) < 0x0001 || 18385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM16(write_conn_accept_timeout, timeout) > 0xb540) { 18395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); 18405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 18425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->conn_accept_tout = PARAM16(write_conn_accept_timeout, timeout); 18445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 18455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE): 18485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_read_scan_enable(hci); 18495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE): 18525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(write_scan_enable); 18535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: check that the remaining bits are all 0 */ 18555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->device.inquiry_scan = 18565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner !!(PARAM(write_scan_enable, scan_enable) & SCAN_INQUIRY); 18575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->device.page_scan = 18585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner !!(PARAM(write_scan_enable, scan_enable) & SCAN_PAGE); 18595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 18605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CLASS_OF_DEV): 18635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_read_local_class(hci); 18645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV): 18675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(write_class_of_dev); 18685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(hci->device.class, PARAM(write_class_of_dev, dev_class), 18705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner sizeof(PARAM(write_class_of_dev, dev_class))); 18715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 18725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_VOICE_SETTING): 18755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_voice_setting(hci); 18765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING): 18795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(write_voice_setting); 18805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->voice_setting = PARAM(write_voice_setting, voice_setting); 18825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 18835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_HOST_NUMBER_OF_COMPLETED_PACKETS): 18865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < data[0] * 2 + 1) 18875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner goto short_hci; 18885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (i = 0; i < data[0]; i ++) 18905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, 18915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner data[i * 2 + 1] | (data[i * 2 + 2] << 8))) 18925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); 18935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 18945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 18955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQUIRY_MODE): 18965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x40) 18975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * else 18985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * goto unknown_command */ 18995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_read_inquiry_mode(hci); 19005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE): 19035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x80) 19045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * else 19055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * goto unknown_command */ 19065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(write_inquiry_mode); 19075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (PARAM(write_inquiry_mode, mode) > 0x01) { 19095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS); 19105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 19125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.inquiry_mode = PARAM(write_inquiry_mode, mode); 19145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_complete_status(hci, HCI_SUCCESS); 19155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION): 19185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_read_local_version_rp(hci); 19195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_COMMANDS): 19225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_read_local_commands_rp(hci); 19235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES): 19265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_read_local_features_rp(hci); 19275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES): 19305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(read_local_ext_features); 19315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_read_local_ext_features_rp(hci, 19335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner PARAM(read_local_ext_features, page_num)); 19345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE): 19375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_read_buffer_size_rp(hci); 19385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_COUNTRY_CODE): 19415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_read_country_code_rp(hci); 19425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR): 19455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_read_bd_addr_rp(hci); 19465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner case cmd_opcode_pack(OGF_STATUS_PARAM, OCF_READ_LINK_QUALITY): 19495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner LENGTH_CHECK(read_link_quality); 19505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_link_quality_rp(hci, PARAMHANDLE(read_link_quality)); 19525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner default: 19555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_UNKNOWN_COMMAND); 19565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner short_hci: 19595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: HCI packet too short (%iB)\n", 19605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__, length); 19615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_status(hci, HCI_INVALID_PARAMETERS); 19625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner break; 19635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 19645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 19655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* We could perform fragmentation here, we can't do "recombination" because 19675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * at this layer the length of the payload is not know ahead, so we only 19685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * know that a packet contained the last fragment of the SDU when the next 19695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * SDU starts. */ 19705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle, 19715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const uint8_t *data, int start, int len) 19725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 19735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct hci_acl_hdr *pkt = (void *) hci->acl_buf; 19745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: packet flags */ 19765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: avoid memcpy'ing */ 19775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) { 19795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: can't take ACL packets %i bytes long\n", 19805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__, len); 19815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 19825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 19835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner memcpy(hci->acl_buf + HCI_ACL_HDR_SIZE, data, len); 19845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pkt->handle = cpu_to_le16( 19865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner acl_handle_pack(handle, start ? ACL_START : ACL_CONT)); 19875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner pkt->dlen = cpu_to_le16(len); 19885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->info.acl_recv(hci->info.opaque, 19895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->acl_buf, len + HCI_ACL_HDR_SIZE); 19905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 19915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink, 19935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const uint8_t *data, int start, int len) 19945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 19955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink; 19965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 19975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_lmp_acl_data(hci_from_device(btlink->slave), 19985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->handle, data, start, len); 19995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 20005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_lmp_acl_data_host(struct bt_link_s *link, 20025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const uint8_t *data, int start, int len) 20035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 20045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_lmp_acl_data(hci_from_device(link->host), 20055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link->handle, data, start, len); 20065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 20075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_submit_acl(struct HCIInfo *info, 20095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const uint8_t *data, int length) 20105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 20115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_info(info); 20125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle; 20135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int datalen, flags; 20145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_link_s *link; 20155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < HCI_ACL_HDR_SIZE) { 20175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: ACL packet too short (%iB)\n", 20185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__, length); 20195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 20205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 20215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner handle = acl_handle((data[1] << 8) | data[0]); 20235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner flags = acl_flags((data[1] << 8) | data[0]); 20245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner datalen = (data[3] << 8) | data[2]; 20255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner data += HCI_ACL_HDR_SIZE; 20265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner length -= HCI_ACL_HDR_SIZE; 20275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, handle)) { 20295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid ACL handle %03x\n", 20305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__, handle); 20315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: signal an error */ 20325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 20335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 20345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner handle &= ~HCI_HANDLE_OFFSET; 20355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (datalen > length) { 20375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: ACL packet too short (%iB < %iB)\n", 20385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__, length, datalen); 20395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 20405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 20415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner link = hci->lm.handle[handle].link; 20435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((flags & ~3) == ACL_ACTIVE_BCAST) { 20455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!hci->asb_handle) 20465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->asb_handle = handle; 20475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else if (handle != hci->asb_handle) { 20485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: Bad handle %03x in Active Slave Broadcast\n", 20495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__, handle); 20505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: signal an error */ 20515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 20525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 20535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO */ 20555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 20565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((flags & ~3) == ACL_PICO_BCAST) { 20585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!hci->psb_handle) 20595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->psb_handle = handle; 20605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else if (handle != hci->psb_handle) { 20615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: Bad handle %03x in Parked Slave Broadcast\n", 20625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__, handle); 20635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: signal an error */ 20645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 20655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 20665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO */ 20685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 20695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: increase counter and send EVT_NUM_COMP_PKTS */ 20715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_event_num_comp_pkts(hci, handle | HCI_HANDLE_OFFSET, 1); 20725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Do this last as it can trigger further events even in this HCI */ 20745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->lm.handle[handle].lmp_acl_data(link, data, 20755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner (flags & 3) == ACL_START, length); 20765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 20775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_submit_sco(struct HCIInfo *info, 20795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner const uint8_t *data, int length) 20805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 20815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_info(info); 20825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner uint16_t handle; 20835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int datalen; 20845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (length < 3) 20865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 20875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner handle = acl_handle((data[1] << 8) | data[0]); 20895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner datalen = data[2]; 20905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner length -= 3; 20915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (bt_hci_handle_bad(hci, handle)) { 20935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: invalid SCO handle %03x\n", 20945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__, handle); 20955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 20965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 20975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 20985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (datalen > length) { 20995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fprintf(stderr, "%s: SCO packet too short (%iB < %iB)\n", 21005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner __FUNCTION__, length, datalen); 21015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 21025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 21035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO */ 21055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: increase counter and send EVT_NUM_COMP_PKTS if synchronous 21075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Flow Control is enabled. 21085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * (See Read/Write_Synchronous_Flow_Control_Enable on page 513 and 21095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * page 514.) */ 21105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 21115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic uint8_t *bt_hci_evt_packet(void *opaque) 21135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 21145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: allocate a packet from upper layer */ 21155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *s = opaque; 21165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return s->evt_buf; 21185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 21195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_evt_submit(void *opaque, int len) 21215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 21225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: notify upper layer */ 21235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *s = opaque; 21245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->info.evt_recv(s->info.opaque, s->evt_buf, len); 21265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 21275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int bt_hci_bdaddr_set(struct HCIInfo *info, const uint8_t *bd_addr) 21295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 21305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_info(info); 21315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bacpy(&hci->device.bd_addr, (const bdaddr_t *) bd_addr); 21335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return 0; 21345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 21355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_done(struct HCIInfo *info); 21375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_destroy(struct bt_device_s *dev) 21385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 21395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_device(dev); 21405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_done(&hci->info); 21425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 21435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct HCIInfo *bt_new_hci(struct bt_scatternet_s *net) 21455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 21465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *s = qemu_mallocz(sizeof(struct bt_hci_s)); 21475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21485973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner s->lm.inquiry_done = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_done, s); 21495973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner s->lm.inquiry_next = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_next, s); 21505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->conn_accept_timer = 21515973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner qemu_new_timer_ns(vm_clock, bt_hci_conn_accept_timeout, s); 21525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->evt_packet = bt_hci_evt_packet; 21545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->evt_submit = bt_hci_evt_submit; 21555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->opaque = s; 21565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_device_init(&s->device, net); 21585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->device.lmp_connection_request = bt_hci_lmp_connection_request; 21595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->device.lmp_connection_complete = bt_hci_lmp_connection_complete; 21605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->device.lmp_disconnect_master = bt_hci_lmp_disconnect_host; 21615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->device.lmp_disconnect_slave = bt_hci_lmp_disconnect_slave; 21625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->device.lmp_acl_data = bt_hci_lmp_acl_data_slave; 21635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->device.lmp_acl_resp = bt_hci_lmp_acl_data_host; 21645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->device.lmp_mode_change = bt_hci_lmp_mode_change_slave; 21655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Keep updated! */ 21675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Also keep in sync with supported commands bitmask in 21685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * bt_hci_read_local_commands_rp */ 21695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->device.lmp_caps = 0x8000199b7e85355fll; 21705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_reset(s); 21725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->info.cmd_send = bt_submit_hci; 21745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->info.sco_send = bt_submit_sco; 21755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->info.acl_send = bt_submit_acl; 21765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->info.bdaddr_set = bt_hci_bdaddr_set; 21775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner s->device.handle_destroy = bt_hci_destroy; 21795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return &s->info; 21815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 21825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bt_hci_done(struct HCIInfo *info) 21845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{ 21855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct bt_hci_s *hci = hci_from_info(info); 21865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner int handle; 21875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_device_done(&hci->device); 21895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hci->device.lmp_name) 21915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free((void *) hci->device.lmp_name); 21925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 21935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* Be gentle and send DISCONNECT to all connected peers and those 21945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * currently waiting for us to accept or reject a connection request. 21955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * This frees the links. */ 21965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (hci->conn_req_host) { 21975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_connection_reject(hci, 21985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner hci->conn_req_host, HCI_OE_POWER_OFF); 21995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner return; 22005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner } 22015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 22025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner for (handle = HCI_HANDLE_OFFSET; 22035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner handle < (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX); handle ++) 22045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (!bt_hci_handle_bad(hci, handle)) 22055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner bt_hci_disconnect(hci, handle, HCI_OE_POWER_OFF); 22065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 22075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner /* TODO: this is not enough actually, there may be slaves from whom 22085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * we have requested a connection who will soon (or not) respond with 22095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * an accept or a reject, so we should also check if hci->lm.connecting 22105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * is non-zero and if so, avoid freeing the hci but otherwise disappear 22115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * from all qemu social life (e.g. stop scanning and request to be 22125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * removed from s->device.net) and arrange for 22135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * s->device.lmp_connection_complete to free the remaining bits once 22145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * hci->lm.awaiting_bdaddr[] is empty. */ 22155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 22165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free_timer(hci->lm.inquiry_done); 22175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free_timer(hci->lm.inquiry_next); 22185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free_timer(hci->conn_accept_timer); 22195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 22205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner qemu_free(hci); 22215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} 2222