emulator: Rework command handling
Luiz Augusto von Dentz
maintainerPATCH 1/1 emulator: Rework command handling
From: Luiz Augusto von Dentz <[email protected]>
This create command tables per version/supported command bits to make it easier to keep them in sync.
--- emulator/btdev.c | 6973 +++++++++++++++++++++++++--------------------- 1 file changed, 3815 insertions(+), 3158 deletions(-)
emulator/btdev.c +3815 -3158
@@ -20,6 +20,7 @@#include <alloca.h> #include <sys/uio.h> #include <stdint.h> +#include <errno.h> #include "lib/bluetooth.h" #include "lib/hci.h"
@@ -36,6 +37,7 @@#define ACL_HANDLE 42#define ISO_HANDLE 44 +#define SCO_HANDLE 257struct hook {btdev_hook_func handler;
@@ -89,6 +91,7 @@ struct btdev {uint8_t random_addr[6 ];uint8_t le_features[8 ];uint8_t le_states[8 ]; +const struct btdev_cmd *cmds;uint16_t default_link_policy;uint8_t event_mask[8 ];
@@ -271,25 +274,1804 @@ static void get_bdaddr(uint16_t id, uint8_t index, uint8_t *bdaddr) bdaddr[5 ] =0x00 ; } +struct btdev_cmd { +uint16_t opcode; +int (*func)(struct btdev *dev,const void *data,uint8_t len); +int (*complete)(struct btdev *dev,const void *data,uint8_t len); +}; + +#define CMD (_opcode, _func, _complete) \ + { \ + .opcode = _opcode, \ + .func = _func, \ + .complete = _complete, \ + } + +static void send_packet (struct btdev *btdev,const struct iovec *iov, +int iovlen) +{ +int i; + +if (!btdev->send_handler) +return ; + +for (i =0 ; i < iovlen; i++) { +if (!i) +util_hexdump ('<' , iov[i].iov_base, iov[i].iov_len, + btdev->debug_callback, btdev->debug_data); +else +util_hexdump (' ' , iov[i].iov_base, iov[i].iov_len, + btdev->debug_callback, btdev->debug_data); + } + + btdev->send_handler (iov, iovlen, btdev->send_data); +} + +static void send_cmd (struct btdev *btdev,uint8_t evt,uint16_t opcode, +const struct iovec *iov,int iovlen) +{ +struct bt_hci_evt_hdr hdr; +struct iovec iov2[2 + iovlen]; +uint8_t pkt =BT_H4_EVT_PKT ; +int i; + +util_debug (btdev->debug_callback, btdev->debug_data, +"event 0x%02x opcode 0x%04x" , evt, opcode); + + iov2[0 ].iov_base = &pkt; + iov2[0 ].iov_len =sizeof (pkt); + + hdr.evt = evt; + hdr.plen =0 ; + + iov2[1 ].iov_base = &hdr; + iov2[1 ].iov_len =sizeof (hdr); + +for (i =0 ; i < iovlen; i++) { + hdr.plen += iov[i].iov_len; + iov2[2 + i].iov_base = iov[i].iov_base; + iov2[2 + i].iov_len = iov[i].iov_len; + } + +if (run_hooks (btdev,BTDEV_HOOK_POST_CMD , opcode, iov[i -1 ].iov_base, + iov[i -1 ].iov_len)) +send_packet (btdev, iov2,2 + iovlen); +} + +static void cmd_complete (struct btdev *btdev,uint16_t opcode, +const void *data,uint8_t len) +{ +struct bt_hci_evt_cmd_complete cc; +struct iovec iov[2 ]; + + cc.ncmd =0x01 ; + cc.opcode =cpu_to_le16 (opcode); + + iov[0 ].iov_base = &cc; + iov[0 ].iov_len =sizeof (cc); + + iov[1 ].iov_base = (void *) data; + iov[1 ].iov_len = len; + +send_cmd (btdev,BT_HCI_EVT_CMD_COMPLETE , opcode, iov,2 ); +} + +static int cmd_set_event_mask (struct btdev *dev,const void *data,uint8_t len) +{ +const struct bt_hci_cmd_set_event_mask *cmd = data; +uint8_t status; + +memcpy (dev->event_mask, cmd->mask,8 ); + status =BT_HCI_ERR_SUCCESS ; + +cmd_complete (dev,BT_HCI_CMD_SET_EVENT_MASK , &status,sizeof (status)); + +return 0 ; +} + +static void btdev_reset (struct btdev *btdev) +{ +/* FIXME: include here clearing of all states that should be +* cleared upon HCI_Reset +*/ + + btdev->le_scan_enable =0x00 ; + btdev->le_adv_enable =0x00 ; +} + +static int cmd_reset (struct btdev *dev,const void *data,uint8_t len) +{ +uint8_t status; + +btdev_reset (dev); + status =BT_HCI_ERR_SUCCESS ; + +cmd_complete (dev,BT_HCI_CMD_RESET , &status,sizeof (status)); + +return 0 ; +} + +static int cmd_read_local_version (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_local_version rsp; + +memset (&rsp,0 ,sizeof (rsp)); + + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.hci_ver = dev->version; + rsp.hci_rev =cpu_to_le16 (dev->revision); + rsp.lmp_ver = dev->version; + rsp.manufacturer =cpu_to_le16 (dev->manufacturer); + rsp.lmp_subver =cpu_to_le16 (dev->revision); + +cmd_complete (dev,BT_HCI_CMD_READ_LOCAL_VERSION , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_read_local_commands (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_local_commands rsp; + + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.commands, dev->commands,64 ); + +cmd_complete (dev,BT_HCI_CMD_READ_LOCAL_COMMANDS , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_read_local_features (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_local_features rsp; + + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.features, dev->features,8 ); + +cmd_complete (dev,BT_HCI_CMD_READ_LOCAL_FEATURES , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_read_buffer_size (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_buffer_size rsp; + + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.acl_mtu =cpu_to_le16 (dev->acl_mtu); + rsp.sco_mtu =0 ; + rsp.acl_max_pkt =cpu_to_le16 (dev->acl_max_pkt); + rsp.sco_max_pkt =cpu_to_le16 (0 ); + +cmd_complete (dev,BT_HCI_CMD_READ_BUFFER_SIZE , &rsp,sizeof (rsp)); + +return 0 ; +} + +#define CMD_COMMON_ALL \ + CMD(BT_HCI_CMD_SET_EVENT_MASK, cmd_set_event_mask, NULL), \ + CMD(BT_HCI_CMD_RESET, cmd_reset, NULL), \ + CMD(BT_HCI_CMD_READ_LOCAL_VERSION, cmd_read_local_version, NULL), \ + CMD(BT_HCI_CMD_READ_LOCAL_COMMANDS, cmd_read_local_commands, NULL), \ + CMD(BT_HCI_CMD_READ_LOCAL_FEATURES, cmd_read_local_features, NULL), \ + CMD(BT_HCI_CMD_READ_BUFFER_SIZE, cmd_read_buffer_size, NULL) +static void set_common_commands_all (struct btdev *btdev) { - btdev->commands[5 ] |=0x40 ;/* Set Event Mask */ - btdev->commands[5 ] |=0x80 ;/* Reset */ - btdev->commands[14 ] |=0x08 ;/* Read Local Version */ - btdev->commands[14 ] |=0x10 ;/* Read Local Supported Commands */ - btdev->commands[14 ] |=0x20 ;/* Read Local Supported Features */ - btdev->commands[14 ] |=0x80 ;/* Read Buffer Size */ + btdev->commands[5 ] |=0x40 ;/* Set Event Mask */ + btdev->commands[5 ] |=0x80 ;/* Reset */ + btdev->commands[14 ] |=0x08 ;/* Read Local Version */ + btdev->commands[14 ] |=0x10 ;/* Read Local Supported Commands */ + btdev->commands[14 ] |=0x20 ;/* Read Local Supported Features */ + btdev->commands[14 ] |=0x80 ;/* Read Buffer Size */ +} + +static void cmd_status (struct btdev *btdev,uint8_t status,uint16_t opcode) +{ +struct bt_hci_evt_cmd_status cs; +struct iovec iov; + + cs.status = status; + cs.ncmd =0x01 ; + cs.opcode =cpu_to_le16 (opcode); + + iov.iov_base = &cs; + iov.iov_len =sizeof (cs); + +send_cmd (btdev,BT_HCI_EVT_CMD_STATUS , opcode, &iov,1 ); +} + +static int cmd_disconnect (struct btdev *dev,const void *data,uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_DISCONNECT ); + +return 0 ; +} + +static void send_event (struct btdev *btdev,uint8_t event, +const void *data,uint8_t len) +{ +struct bt_hci_evt_hdr hdr; +struct iovec iov[3 ]; +uint8_t pkt =BT_H4_EVT_PKT ; + +util_debug (btdev->debug_callback, btdev->debug_data, +"event 0x%02x" , event); + + iov[0 ].iov_base = &pkt; + iov[0 ].iov_len =sizeof (pkt); + + hdr.evt = event; + hdr.plen = len; + + iov[1 ].iov_base = &hdr; + iov[1 ].iov_len =sizeof (hdr); + +if (len >0 ) { + iov[2 ].iov_base = (void *) data; + iov[2 ].iov_len = len; + } + +if (run_hooks (btdev,BTDEV_HOOK_POST_EVT , event, data, len)) +send_packet (btdev, iov, len >0 ?3 :2 ); +} + +static int cmd_disconnect_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_disconnect *cmd = data; +struct bt_hci_evt_disconnect_complete rsp; +struct btdev *remote = dev->conn; + +memset (&rsp,0 ,sizeof (rsp)); + +if (!remote) { + rsp.status =BT_HCI_ERR_UNKNOWN_CONN_ID ; + rsp.handle =cpu_to_le16 (cmd->handle); + rsp.reason =0x00 ; + +send_event (dev,BT_HCI_EVT_DISCONNECT_COMPLETE , &rsp, +sizeof (rsp)); +return 0 ; + } + + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.handle =cpu_to_le16 (cmd->handle); + rsp.reason = cmd->reason; + +if (rsp.handle ==ACL_HANDLE ) { + dev->conn =NULL ; + remote->conn =NULL ; + } + +send_event (dev,BT_HCI_EVT_DISCONNECT_COMPLETE , &rsp,sizeof (rsp)); +send_event (remote,BT_HCI_EVT_DISCONNECT_COMPLETE , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_remote_version (struct btdev *dev,const void *data,uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_READ_REMOTE_VERSION ); + +return 0 ; +} + +static int cmd_remote_version_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_read_remote_version *cmd = data; +struct bt_hci_evt_remote_version_complete ev; + +memset (&ev,0 ,sizeof (ev)); + +if (dev->conn) { + ev.status =BT_HCI_ERR_SUCCESS ; + ev.handle =cpu_to_le16 (cmd->handle); + ev.lmp_ver = dev->conn->version; + ev.manufacturer =cpu_to_le16 (dev->conn->manufacturer); + ev.lmp_subver =cpu_to_le16 (dev->conn->revision); + }else { + ev.status =BT_HCI_ERR_UNKNOWN_CONN_ID ; + ev.handle =cpu_to_le16 (cmd->handle); + ev.lmp_ver =0x00 ; + ev.manufacturer =cpu_to_le16 (0 ); + ev.lmp_subver =cpu_to_le16 (0 ); + } + +send_event (dev,BT_HCI_EVT_REMOTE_VERSION_COMPLETE , &ev,sizeof (ev)); + +return 0 ; +} + +static int cmd_set_host_flowctl (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_set_host_flow_control *cmd = data; +uint8_t status; + +if (cmd->enable >0x03 ) { + status =BT_HCI_ERR_INVALID_PARAMETERS ; + }else { + dev->host_flow_control = cmd->enable; + status =BT_HCI_ERR_SUCCESS ; + } + +cmd_complete (dev,BT_HCI_CMD_SET_HOST_FLOW_CONTROL , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_host_buffer_size (struct btdev *dev,const void *data, +uint8_t len) +{ +uint8_t status =BT_HCI_ERR_SUCCESS ; + +cmd_complete (dev,BT_HCI_CMD_HOST_BUFFER_SIZE , &status,sizeof (status)); + +return 0 ; +} + +static int cmd_read_bdaddr (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_read_bd_addr rsp; + +memset (&rsp,0 ,sizeof (rsp)); + + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.bdaddr, dev->bdaddr,6 ); + +cmd_complete (dev,BT_HCI_CMD_READ_BD_ADDR , &rsp,sizeof (rsp)); + +return 0 ; +} + +#define CMD_COMMON_BREDR_LE \ + CMD(BT_HCI_CMD_DISCONNECT, cmd_disconnect, cmd_disconnect_complete), \ + CMD(BT_HCI_CMD_READ_REMOTE_VERSION, cmd_remote_version, \ + cmd_remote_version_complete), \ + CMD(BT_HCI_CMD_SET_HOST_FLOW_CONTROL, cmd_set_host_flowctl, NULL), \ + CMD(BT_HCI_CMD_HOST_BUFFER_SIZE, cmd_host_buffer_size, NULL), \ + CMD(BT_HCI_CMD_READ_BD_ADDR, cmd_read_bdaddr, NULL) + +static void set_common_commands_bredrle (struct btdev *btdev) +{ + btdev->commands[0 ] |=0x20 ;/* Disconnect */ + btdev->commands[2 ] |=0x80 ;/* Read Remote Version Information */ + btdev->commands[10 ] |=0x20 ;/* Set Host Flow Control */ + btdev->commands[10 ] |=0x40 ;/* Host Buffer Size */ + btdev->commands[15 ] |=0x02 ;/* Read BD ADDR */ +} + +static int cmd_inquiry (struct btdev *dev,const void *data,uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_INQUIRY ); + +return 0 ; +} + +static bool inquiry_callback (void *user_data) +{ +struct inquiry_data *data = user_data; +struct btdev *btdev = data->btdev; +struct bt_hci_evt_inquiry_complete ic; +int sent = data->sent_count; +int i; + +/*Report devices only once and wait for inquiry timeout*/ +if (data->iter ==MAX_BTDEV_ENTRIES ) +return true; + +for (i = data->iter; i <MAX_BTDEV_ENTRIES ; i++) { +/*Lets sent 10 inquiry results at once */ +if (sent +10 == data->sent_count) +break ; + +if (!btdev_list[i] || btdev_list[i] == btdev) +continue ; + +if (!(btdev_list[i]->scan_enable &0x02 )) +continue ; + +if (btdev->inquiry_mode ==0x02 && + btdev_list[i]->ext_inquiry_rsp[0 ]) { +struct bt_hci_evt_ext_inquiry_result ir; + + ir.num_resp =0x01 ; +memcpy (ir.bdaddr, btdev_list[i]->bdaddr,6 ); + ir.pscan_rep_mode =0x00 ; + ir.pscan_period_mode =0x00 ; +memcpy (ir.dev_class, btdev_list[i]->dev_class,3 ); + ir.clock_offset =0x0000 ; + ir.rssi =-60 ; +memcpy (ir.data, btdev_list[i]->ext_inquiry_rsp,240 ); + +send_event (btdev,BT_HCI_EVT_EXT_INQUIRY_RESULT , + &ir,sizeof (ir)); + data->sent_count++; +continue ; + } + +if (btdev->inquiry_mode >0x00 ) { +struct bt_hci_evt_inquiry_result_with_rssi ir; + + ir.num_resp =0x01 ; +memcpy (ir.bdaddr, btdev_list[i]->bdaddr,6 ); + ir.pscan_rep_mode =0x00 ; + ir.pscan_period_mode =0x00 ; +memcpy (ir.dev_class, btdev_list[i]->dev_class,3 ); + ir.clock_offset =0x0000 ; + ir.rssi =-60 ; + +send_event (btdev,BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI , + &ir,sizeof (ir)); + data->sent_count++; + }else { +struct bt_hci_evt_inquiry_result ir; + + ir.num_resp =0x01 ; +memcpy (ir.bdaddr, btdev_list[i]->bdaddr,6 ); + ir.pscan_rep_mode =0x00 ; + ir.pscan_period_mode =0x00 ; + ir.pscan_mode =0x00 ; +memcpy (ir.dev_class, btdev_list[i]->dev_class,3 ); + ir.clock_offset =0x0000 ; + +send_event (btdev,BT_HCI_EVT_INQUIRY_RESULT , + &ir,sizeof (ir)); + data->sent_count++; + } + } + data->iter = i; + +/* Check if we sent already required amount of responses*/ +if (data->num_resp && data->sent_count == data->num_resp) + goto finish; + +return true; + +finish: +/* Note that destroy will be called */ + ic.status =BT_HCI_ERR_SUCCESS ; +send_event (btdev,BT_HCI_EVT_INQUIRY_COMPLETE , &ic,sizeof (ic)); + +return false; +} + +static void inquiry_destroy (void *user_data) +{ +struct inquiry_data *data = user_data; +struct btdev *btdev = data->btdev; + +if (!btdev) + goto finish; + + btdev->inquiry_id =0 ; + +if (btdev->inquiry_timeout_id >0 ) { +timeout_remove (btdev->inquiry_timeout_id); + btdev->inquiry_timeout_id =0 ; + } + +finish: +free (data); +} + +static bool inquiry_timeout (void *user_data) +{ +struct inquiry_data *data = user_data; +struct btdev *btdev = data->btdev; +struct bt_hci_evt_inquiry_complete ic; + +timeout_remove (btdev->inquiry_id); + btdev->inquiry_timeout_id =0 ; + +/* Inquiry is stopped, send Inquiry complete event. */ + ic.status =BT_HCI_ERR_SUCCESS ; +send_event (btdev,BT_HCI_EVT_INQUIRY_COMPLETE , &ic,sizeof (ic)); + +return false; +} + +static int cmd_inquiry_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_inquiry *cmd = data; +struct inquiry_data *idata; +struct bt_hci_evt_inquiry_complete ic; +int status =BT_HCI_ERR_HARDWARE_FAILURE ; +unsigned int inquiry_len_ms; + +if (dev->inquiry_id >0 ) { + status =BT_HCI_ERR_COMMAND_DISALLOWED ; + goto failed; + } + + idata =malloc0 (sizeof (*idata)); +if (!idata) + goto failed; + + idata->btdev = dev; + idata->num_resp = cmd->num_resp; + +/* Add timeout to cancel inquiry */ + inquiry_len_ms =1280 * cmd->length; +if (inquiry_len_ms) + dev->inquiry_timeout_id =timeout_add (inquiry_len_ms, + inquiry_timeout, + idata,NULL ); + + dev->inquiry_id =timeout_add (DEFAULT_INQUIRY_INTERVAL , + inquiry_callback, idata, + inquiry_destroy); +/* Return if success */ +if (dev->inquiry_id >0 ) +return 0 ; + +failed: + ic.status = status; +send_event (dev,BT_HCI_EVT_INQUIRY_COMPLETE , &ic,sizeof (ic)); + +return 0 ; +} + +static int cmd_inquiry_cancel (struct btdev *dev,const void *data,uint8_t len) +{ +uint8_t status; + +if (!dev->inquiry_id) { + status =BT_HCI_ERR_COMMAND_DISALLOWED ; + goto done; + } + +timeout_remove (dev->inquiry_timeout_id); + dev->inquiry_timeout_id =0 ; +timeout_remove (dev->inquiry_id); + dev->inquiry_id =0 ; + + status =BT_HCI_ERR_SUCCESS ; + +done: +cmd_complete (dev,BT_HCI_CMD_INQUIRY_CANCEL , &status,sizeof (status)); + +return 0 ; +} + +static int cmd_create_conn (struct btdev *dev,const void *data,uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_CREATE_CONN ); + +return 0 ; +} + +static void conn_complete (struct btdev *btdev, +const uint8_t *bdaddr,uint8_t status) +{ +struct bt_hci_evt_conn_complete cc; + +if (!status) { +struct btdev *remote =find_btdev_by_bdaddr (bdaddr); + + btdev->conn = remote; + remote->conn = btdev; + + cc.status = status; +memcpy (cc.bdaddr, btdev->bdaddr,6 ); + cc.encr_mode =0x00 ; + + cc.handle =cpu_to_le16 (ACL_HANDLE ); + cc.link_type =0x01 ; + +send_event (remote,BT_HCI_EVT_CONN_COMPLETE , &cc,sizeof (cc)); + + cc.handle =cpu_to_le16 (ACL_HANDLE ); + cc.link_type =0x01 ; + }else { + cc.handle =cpu_to_le16 (0x0000 ); + cc.link_type =0x01 ; + } + + cc.status = status; +memcpy (cc.bdaddr, bdaddr,6 ); + cc.encr_mode =0x00 ; + +send_event (btdev,BT_HCI_EVT_CONN_COMPLETE , &cc,sizeof (cc)); +} + +static int cmd_create_conn_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_create_conn *cmd = data; +struct btdev *remote =find_btdev_by_bdaddr (cmd->bdaddr); + +if (remote && remote->scan_enable &0x02 ) { +struct bt_hci_evt_conn_request cr; + +memcpy (cr.bdaddr, dev->bdaddr,6 ); +memcpy (cr.dev_class, dev->dev_class,3 ); + cr.link_type =0x01 ; + +send_event (remote,BT_HCI_EVT_CONN_REQUEST , &cr,sizeof (cr)); + }else { +conn_complete (dev, cmd->bdaddr,BT_HCI_ERR_PAGE_TIMEOUT ); + } + +return 0 ; +} + +static int cmd_add_sco_conn (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_evt_conn_complete cc; + +if (!dev->conn) +return 0 ; + + cc.status =BT_HCI_ERR_SUCCESS ; +memcpy (cc.bdaddr, dev->conn->bdaddr,6 ); + cc.handle =cpu_to_le16 (SCO_HANDLE ); + cc.link_type =0x00 ; + cc.encr_mode =0x00 ; + +send_event (dev,BT_HCI_EVT_CONN_COMPLETE , &cc,sizeof (cc)); + +return 0 ; +} + +static int cmd_create_conn_cancel (struct btdev *dev,const void *data, +uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_CREATE_CONN_CANCEL ); + +return 0 ; +} + +static int cmd_create_conn_cancel_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_create_conn_cancel *cmd = data; + +conn_complete (dev, cmd->bdaddr,BT_HCI_ERR_UNKNOWN_CONN_ID ); + +return 0 ; +} + +static int cmd_accept_conn (struct btdev *dev,const void *data,uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_ACCEPT_CONN_REQUEST ); + +return 0 ; +} + +static int cmd_accept_conn_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_accept_conn_request *cmd = data; +struct btdev *remote =find_btdev_by_bdaddr (cmd->bdaddr); + +if (!remote) +return 0 ; + +if (dev->auth_enable || remote->auth_enable) +send_event (remote,BT_HCI_EVT_LINK_KEY_REQUEST , dev->bdaddr,6 ); +else +conn_complete (dev, cmd->bdaddr,BT_HCI_ERR_SUCCESS ); + +return 0 ; +} + +static int cmd_reject_conn (struct btdev *dev,const void *data,uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_REJECT_CONN_REQUEST ); + +return 0 ; +} + +static int cmd_reject_conn_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_reject_conn_request *cmd = data; + +conn_complete (dev, cmd->bdaddr,BT_HCI_ERR_UNKNOWN_CONN_ID ); + +return 0 ; +} + +static int cmd_link_key_reply (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_link_key_request_reply rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.bdaddr, data,6 ); +cmd_complete (dev,BT_HCI_CMD_LINK_KEY_REQUEST_REPLY , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_link_key_reply_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_link_key_request_reply *cmd = data; +struct btdev *remote = dev->conn; +struct bt_hci_evt_auth_complete ev; + +memcpy (dev->link_key, cmd->link_key,16 ); + +if (!remote) { + remote =find_btdev_by_bdaddr (cmd->bdaddr); +if (!remote) +return 0 ; + } + +if (!memcmp (remote->link_key,LINK_KEY_NONE ,16 )) { +send_event (remote,BT_HCI_EVT_LINK_KEY_REQUEST , dev->bdaddr,6 ); +return 0 ; + } + + ev.handle =cpu_to_le16 (ACL_HANDLE ); + +if (!memcmp (dev->link_key, remote->link_key,16 )) + ev.status =BT_HCI_ERR_SUCCESS ; +else + ev.status =BT_HCI_ERR_AUTH_FAILURE ; + +send_event (dev,BT_HCI_EVT_AUTH_COMPLETE , &ev,sizeof (ev)); +send_event (remote,BT_HCI_EVT_AUTH_COMPLETE , &ev,sizeof (ev)); + +return 0 ; +} + +static int cmd_link_key_neg_reply (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_link_key_request_neg_reply rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.bdaddr, data,6 ); +cmd_complete (dev,BT_HCI_CMD_LINK_KEY_REQUEST_NEG_REPLY , &rsp, +sizeof (rsp)); + +return 0 ; +} + +static bool use_ssp (struct btdev *btdev1,struct btdev *btdev2) +{ +if (btdev1->auth_enable || btdev2->auth_enable) +return false; + +return (btdev1->simple_pairing_mode && btdev2->simple_pairing_mode); +} + +static int cmd_link_key_neg_reply_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_link_key_request_neg_reply *cmd = data; +struct btdev *remote = dev->conn; + +if (!remote) { + remote =find_btdev_by_bdaddr (cmd->bdaddr); +if (!remote) +return 0 ; + } + +if (use_ssp (dev, remote)) { +struct bt_hci_evt_io_capability_request io_req; + +memcpy (io_req.bdaddr, cmd->bdaddr,6 ); +send_event (dev,BT_HCI_EVT_IO_CAPABILITY_REQUEST , &io_req, +sizeof (io_req)); + }else { +struct bt_hci_evt_pin_code_request pin_req; + +memcpy (pin_req.bdaddr, cmd->bdaddr,6 ); +send_event (dev,BT_HCI_EVT_PIN_CODE_REQUEST , &pin_req, +sizeof (pin_req)); + } + +return 0 ; +} + +static int cmd_pin_code_reply (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_pin_code_request_neg_reply rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.bdaddr, data,6 ); +cmd_complete (dev,BT_HCI_CMD_PIN_CODE_REQUEST_REPLY , &rsp,sizeof (rsp)); + +return 0 ; +} + +static uint8_t get_link_key_type (struct btdev *btdev) +{ +struct btdev *remote = btdev->conn; +uint8_t auth, unauth; + +if (!remote) +return 0x00 ; + +if (!btdev->simple_pairing_mode) +return 0x00 ; + +if (btdev->ssp_debug_mode || remote->ssp_debug_mode) +return 0x03 ; + +if (btdev->secure_conn_support && remote->secure_conn_support) { + unauth =0x07 ; + auth =0x08 ; + }else { + unauth =0x04 ; + auth =0x05 ; + } + +if (btdev->io_cap ==0x03 || remote->io_cap ==0x03 ) +return unauth; + +if (!(btdev->auth_req &0x01 ) && !(remote->auth_req &0x01 )) +return unauth; + +/* DisplayOnly only produces authenticated with KeyboardOnly */ +if (btdev->io_cap ==0x00 && remote->io_cap !=0x02 ) +return unauth; + +/* DisplayOnly only produces authenticated with KeyboardOnly */ +if (remote->io_cap ==0x00 && btdev->io_cap !=0x02 ) +return unauth; + +return auth; +} + +static void link_key_notify (struct btdev *btdev,const uint8_t *bdaddr, +const uint8_t *key) +{ +struct bt_hci_evt_link_key_notify ev; + +memcpy (btdev->link_key, key,16 ); + +memcpy (ev.bdaddr, bdaddr,6 ); +memcpy (ev.link_key, key,16 ); + ev.key_type =get_link_key_type (btdev); + +send_event (btdev,BT_HCI_EVT_LINK_KEY_NOTIFY , &ev,sizeof (ev)); +} + +static int cmd_pin_code_reply_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_pin_code_request_reply *cmd = data; +struct bt_hci_evt_auth_complete ev; +struct btdev *remote = dev->conn; + +if (!remote) { + remote =find_btdev_by_bdaddr (cmd->bdaddr); +if (!remote) +return 0 ; + } + +memcpy (dev->pin, cmd->pin_code, cmd->pin_len); + dev->pin_len = cmd->pin_len; + +if (!remote->pin_len) { +struct bt_hci_evt_pin_code_request pin_req; + +memcpy (pin_req.bdaddr, dev->bdaddr,6 ); +send_event (remote,BT_HCI_EVT_PIN_CODE_REQUEST , &pin_req, +sizeof (pin_req)); +return 0 ; + } + +if (dev->pin_len == remote->pin_len && + !memcmp (dev->pin, remote->pin, dev->pin_len)) { +link_key_notify (dev, remote->bdaddr,LINK_KEY_DUMMY ); +link_key_notify (remote, dev->bdaddr,LINK_KEY_DUMMY ); + ev.status =BT_HCI_ERR_SUCCESS ; + }else { + ev.status =BT_HCI_ERR_AUTH_FAILURE ; + } + +if (remote->conn) { + ev.handle =cpu_to_le16 (ACL_HANDLE ); +send_event (remote,BT_HCI_EVT_AUTH_COMPLETE , &ev,sizeof (ev)); + }else { +conn_complete (remote, dev->bdaddr, ev.status); + } + + dev->pin_len =0 ; + remote->pin_len =0 ; + +return 0 ; +} + +static int cmd_pin_code_neg_reply (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_pin_code_request_neg_reply rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.bdaddr, data,6 ); +cmd_complete (dev,BT_HCI_CMD_PIN_CODE_REQUEST_NEG_REPLY , &rsp, +sizeof (rsp)); + +return 0 ; +} + +static int cmd_pin_code_neg_reply_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_pin_code_request_neg_reply *cmd = data; +struct bt_hci_evt_auth_complete ev; +struct btdev *remote = dev->conn; + +if (!remote) { + remote =find_btdev_by_bdaddr (cmd->bdaddr); +if (!remote) +return 0 ; + } + + ev.status =BT_HCI_ERR_PIN_OR_KEY_MISSING ; + ev.handle =cpu_to_le16 (ACL_HANDLE ); + +if (dev->conn) +send_event (dev,BT_HCI_EVT_AUTH_COMPLETE , &ev,sizeof (ev)); +else +conn_complete (dev, cmd->bdaddr,BT_HCI_ERR_PIN_OR_KEY_MISSING ); + +if (remote->conn) { +if (remote->pin_len) +send_event (remote,BT_HCI_EVT_AUTH_COMPLETE , &ev, +sizeof (ev)); + }else { +conn_complete (remote, dev->bdaddr, +BT_HCI_ERR_PIN_OR_KEY_MISSING ); + } + +return 0 ; +} + +static int cmd_auth_requested (struct btdev *dev,const void *data,uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_AUTH_REQUESTED ); + +return 0 ; +} + +static int cmd_auth_requested_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_auth_requested *cmd = data; +struct btdev *remote = dev->conn; + +if (!remote) { +struct bt_hci_evt_auth_complete ev; + + ev.status =BT_HCI_ERR_UNKNOWN_CONN_ID ; + ev.handle =cpu_to_le16 (cmd->handle); + +send_event (dev,BT_HCI_EVT_AUTH_COMPLETE , &ev,sizeof (ev)); + +return 0 ; + } + + dev->auth_init = true; + +send_event (dev,BT_HCI_EVT_LINK_KEY_REQUEST , remote->bdaddr,6 ); + +return 0 ; +} + +static int cmd_set_conn_encrypt (struct btdev *dev,const void *data, +uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_SET_CONN_ENCRYPT ); + +return 0 ; +} + +static void encrypt_change (struct btdev *btdev,uint8_t mode,uint8_t status) +{ +struct bt_hci_evt_encrypt_change ev; + + ev.status = status; + ev.handle =cpu_to_le16 (ACL_HANDLE ); + ev.encr_mode = mode; + +send_event (btdev,BT_HCI_EVT_ENCRYPT_CHANGE , &ev,sizeof (ev)); +} + +static int cmd_set_conn_encrypt_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_set_conn_encrypt *cmd = data; +uint8_t mode; + +if (!dev->conn) +return 0 ; + +if (!cmd->encr_mode) + mode =0x00 ; +else if (dev->secure_conn_support && dev->conn->secure_conn_support) + mode =0x02 ; +else + mode =0x01 ; + +encrypt_change (dev, mode,BT_HCI_ERR_SUCCESS ); +encrypt_change (dev->conn, mode,BT_HCI_ERR_SUCCESS ); + +return 0 ; +} + +static int cmd_remote_name (struct btdev *dev,const void *data,uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_REMOTE_NAME_REQUEST ); + +return 0 ; +} + +static void name_request_complete (struct btdev *btdev, +const uint8_t *bdaddr,uint8_t status) +{ +struct bt_hci_evt_remote_name_request_complete nc; + + nc.status = status; +memcpy (nc.bdaddr, bdaddr,6 ); +memset (nc.name,0 ,248 ); + +if (!status) { +struct btdev *remote =find_btdev_by_bdaddr (bdaddr); + +if (remote) +memcpy (nc.name, remote->name,248 ); +else + nc.status =BT_HCI_ERR_UNKNOWN_CONN_ID ; + } + +send_event (btdev,BT_HCI_EVT_REMOTE_NAME_REQUEST_COMPLETE , + &nc,sizeof (nc)); +} + +static int cmd_remote_name_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_remote_name_request *cmd = data; + +name_request_complete (dev, cmd->bdaddr,BT_HCI_ERR_SUCCESS ); + +return 0 ; +} + +static int cmd_remote_name_cancel (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_remote_name_request_cancel *cmd = data; +struct bt_hci_rsp_remote_name_request_cancel rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.bdaddr, cmd->bdaddr,6 ); +cmd_complete (dev,BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL , &rsp, +sizeof (rsp)); + +return 0 ; +} + +static int cmd_remote_name_cancel_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_remote_name_request_cancel *cmd = data; + +name_request_complete (dev, cmd->bdaddr,BT_HCI_ERR_UNKNOWN_CONN_ID ); + +return 0 ; +} + +static int cmd_read_remote_features (struct btdev *dev,const void *data, +uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_READ_REMOTE_FEATURES ); + +return 0 ; +} + +static int cmd_read_remote_features_complete (struct btdev *dev, +const void *data,uint8_t len) +{ +const struct bt_hci_cmd_read_remote_features *cmd = data; +struct bt_hci_evt_remote_features_complete rfc; + +if (dev->conn) { + rfc.status =BT_HCI_ERR_SUCCESS ; + rfc.handle =cpu_to_le16 (cmd->handle); +memcpy (rfc.features, dev->conn->features,8 ); + }else { + rfc.status =BT_HCI_ERR_UNKNOWN_CONN_ID ; + rfc.handle =cpu_to_le16 (cmd->handle); +memset (rfc.features,0 ,8 ); + } + +send_event (dev,BT_HCI_EVT_REMOTE_FEATURES_COMPLETE , &rfc,sizeof (rfc)); + +return 0 ; +} + +static int cmd_read_remote_ext_features (struct btdev *dev,const void *data, +uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS , +BT_HCI_CMD_READ_REMOTE_EXT_FEATURES ); + +return 0 ; +} + +static void btdev_get_host_features (struct btdev *btdev,uint8_t features[8 ]) +{ +memset (features,0 ,8 ); +if (btdev->simple_pairing_mode) + features[0 ] |=0x01 ; +if (btdev->le_supported) + features[0 ] |=0x02 ; +if (btdev->le_simultaneous) + features[0 ] |=0x04 ; +if (btdev->secure_conn_support) + features[0 ] |=0x08 ; +} + +static int cmd_read_remote_ext_features_compl (struct btdev *dev, +const void *data,uint8_t len) +{ +const struct bt_hci_cmd_read_remote_ext_features *cmd = data; +struct bt_hci_evt_remote_ext_features_complete ev; + +memset (&ev,0 ,sizeof (ev)); + +if (dev->conn && cmd->page <0x02 ) { + ev.handle =cpu_to_le16 (cmd->handle); + ev.page = cmd->page; + ev.max_page =0x01 ; + +switch (cmd->page) { +case 0x00 : + ev.status =BT_HCI_ERR_SUCCESS ; +memcpy (ev.features, dev->conn->features,8 ); +break ; +case 0x01 : + ev.status =BT_HCI_ERR_SUCCESS ; +btdev_get_host_features (dev->conn, ev.features); +break ; +default : + ev.status =BT_HCI_ERR_INVALID_PARAMETERS ; +memset (ev.features,0 ,8 ); +break ; + } + }else { + ev.status =BT_HCI_ERR_UNKNOWN_CONN_ID ; + ev.handle =cpu_to_le16 (cmd->handle); + ev.page = cmd->page; + ev.max_page =0x01 ; +memset (ev.features,0 ,8 ); + } + +send_event (dev,BT_HCI_EVT_REMOTE_EXT_FEATURES_COMPLETE , &ev, +sizeof (ev)); + +return 0 ; +} + +static int cmd_read_clock_offset (struct btdev *dev,const void *data, +uint8_t len) +{ +cmd_status (dev,BT_HCI_ERR_SUCCESS ,BT_HCI_CMD_READ_CLOCK_OFFSET ); + +return 0 ; +} + +static int cmd_read_clock_offset_complete (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_read_clock_offset *cmd = data; +struct bt_hci_evt_clock_offset_complete ev; + +memset (&ev,0 ,sizeof (ev)); + +if (dev->conn) { + ev.status =BT_HCI_ERR_SUCCESS ; + ev.handle =cpu_to_le16 (cmd->handle); + ev.clock_offset =0 ; + }else { + ev.status =BT_HCI_ERR_UNKNOWN_CONN_ID ; + ev.handle =cpu_to_le16 (cmd->handle); + ev.clock_offset =0 ; + } + +send_event (dev,BT_HCI_EVT_CLOCK_OFFSET_COMPLETE , &ev,sizeof (ev)); + +return 0 ; +} + +static int cmd_read_link_policy (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_default_link_policy rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.policy =cpu_to_le16 (dev->default_link_policy); +cmd_complete (dev,BT_HCI_CMD_READ_DEFAULT_LINK_POLICY , &rsp, +sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_link_policy (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_write_default_link_policy *cmd = data; +uint8_t status; + + dev->default_link_policy =le16_to_cpu (cmd->policy); + status =BT_HCI_ERR_SUCCESS ; +cmd_complete (dev,BT_HCI_CMD_WRITE_DEFAULT_LINK_POLICY , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_set_event_filter (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_set_event_filter *cmd = data; +uint8_t status; + + dev->event_filter = cmd->type; + status =BT_HCI_ERR_SUCCESS ; +cmd_complete (dev,BT_HCI_CMD_SET_EVENT_FILTER , &status,sizeof (status)); + +return 0 ; +} + +static int cmd_read_link_key (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_read_stored_link_key rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.max_num_keys =cpu_to_le16 (0 ); + rsp.num_keys =cpu_to_le16 (0 ); +cmd_complete (dev,BT_HCI_CMD_READ_STORED_LINK_KEY , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_link_key (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_write_stored_link_key rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.num_keys =0 ; +cmd_complete (dev,BT_HCI_CMD_WRITE_STORED_LINK_KEY , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_delete_link_key (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_delete_stored_link_key rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.num_keys =cpu_to_le16 (0 ); +cmd_complete (dev,BT_HCI_CMD_DELETE_STORED_LINK_KEY , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_read_local_name (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_read_local_name rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.name, dev->name,248 ); +cmd_complete (dev,BT_HCI_CMD_READ_LOCAL_NAME , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_local_name (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_write_local_name *cmd = data; +uint8_t status; + +memcpy (dev->name, cmd->name,248 ); + status =BT_HCI_ERR_SUCCESS ; +cmd_complete (dev,BT_HCI_CMD_WRITE_LOCAL_NAME , &status,sizeof (status)); + +return 0 ; +} + +static int cmd_read_accept_timeout (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_conn_accept_timeout rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.timeout =cpu_to_le16 (dev->conn_accept_timeout); +cmd_complete (dev,BT_HCI_CMD_READ_CONN_ACCEPT_TIMEOUT , &rsp, +sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_accept_timeout (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_write_conn_accept_timeout *cmd = data; +uint8_t status; + + dev->conn_accept_timeout =le16_to_cpu (cmd->timeout); + status =BT_HCI_ERR_SUCCESS ; +cmd_complete (dev,BT_HCI_CMD_WRITE_CONN_ACCEPT_TIMEOUT , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_page_timeout (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_page_timeout rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.timeout =cpu_to_le16 (dev->page_timeout); +cmd_complete (dev,BT_HCI_CMD_READ_PAGE_TIMEOUT , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_page_timeout (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_write_page_timeout *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; + + dev->page_timeout =le16_to_cpu (cmd->timeout); +cmd_complete (dev,BT_HCI_CMD_WRITE_PAGE_TIMEOUT , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_scan_enable (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_scan_enable rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.enable = dev->scan_enable; +cmd_complete (dev,BT_HCI_CMD_READ_SCAN_ENABLE , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_scan_enable (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_write_scan_enable *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; + + dev->scan_enable = cmd->enable; +cmd_complete (dev,BT_HCI_CMD_WRITE_SCAN_ENABLE , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_page_scan (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_page_scan_activity rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.interval =cpu_to_le16 (dev->page_scan_interval); + rsp.window =cpu_to_le16 (dev->page_scan_window); +cmd_complete (dev,BT_HCI_CMD_READ_PAGE_SCAN_ACTIVITY , &rsp, +sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_page_scan (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_write_page_scan_activity *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; + + dev->page_scan_interval =le16_to_cpu (cmd->interval); + dev->page_scan_window =le16_to_cpu (cmd->window); +cmd_complete (dev,BT_HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_inquiry_scan (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_inquiry_scan_activity rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.interval =cpu_to_le16 (dev->inquiry_scan_interval); + rsp.window =cpu_to_le16 (dev->inquiry_scan_window); +cmd_complete (dev,BT_HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY , &rsp, +sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_inquiry_scan (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_write_inquiry_scan_activity *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; + + dev->inquiry_scan_interval =le16_to_cpu (cmd->interval); + dev->inquiry_scan_window =le16_to_cpu (cmd->window); +cmd_complete (dev,BT_HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY , &status, +sizeof (status)); + +return 0 ; } -static void set_common_commands_bredrle (struct btdev *btdev) +static int cmd_read_auth_enable (struct btdev *dev,const void *data, +uint8_t len) { - btdev->commands[0 ] |=0x20 ;/* Disconnect */ - btdev->commands[2 ] |=0x80 ;/* Read Remote Version Information */ - btdev->commands[10 ] |=0x20 ;/* Set Host Flow Control */ - btdev->commands[10 ] |=0x40 ;/* Host Buffer Size */ - btdev->commands[15 ] |=0x02 ;/* Read BD ADDR */ +struct bt_hci_rsp_read_auth_enable rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.enable = dev->auth_enable; +cmd_complete (dev,BT_HCI_CMD_READ_AUTH_ENABLE , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_auth_enable (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_write_auth_enable *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; + + dev->auth_enable = cmd->enable; +cmd_complete (dev,BT_HCI_CMD_WRITE_AUTH_ENABLE , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_class (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_read_class_of_dev rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.dev_class, dev->dev_class,3 ); +cmd_complete (dev,BT_HCI_CMD_READ_CLASS_OF_DEV , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_class (struct btdev *dev,const void *data,uint8_t len) +{ +const struct bt_hci_cmd_write_class_of_dev *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; + +memcpy (dev->dev_class, cmd->dev_class,3 ); +cmd_complete (dev,BT_HCI_CMD_WRITE_CLASS_OF_DEV , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_voice (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_read_voice_setting rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.setting =cpu_to_le16 (dev->voice_setting); +cmd_complete (dev,BT_HCI_CMD_READ_VOICE_SETTING , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_voice (struct btdev *dev,const void *data,uint8_t len) +{ +const struct bt_hci_cmd_write_voice_setting *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; + + dev->voice_setting =le16_to_cpu (cmd->setting); +cmd_complete (dev,BT_HCI_CMD_WRITE_VOICE_SETTING , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_num_iac (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_read_num_supported_iac rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.num_iac =0x01 ; +cmd_complete (dev,BT_HCI_CMD_READ_NUM_SUPPORTED_IAC , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_read_current_iac_lap (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_current_iac_lap *rsp; + + rsp =alloca (sizeof (*rsp) +3 ); + rsp->status =BT_HCI_ERR_SUCCESS ; + rsp->num_iac =0x01 ; + rsp->iac_lap[0 ] =0x33 ; + rsp->iac_lap[1 ] =0x8b ; + rsp->iac_lap[2 ] =0x9e ; +cmd_complete (dev,BT_HCI_CMD_READ_CURRENT_IAC_LAP , rsp, +sizeof (*rsp) +3 ); + +return 0 ; +} + +static int cmd_write_current_iac_lap (struct btdev *dev,const void *data, +uint8_t len) +{ +uint8_t status =BT_HCI_ERR_SUCCESS ; + +cmd_complete (dev,BT_HCI_CMD_WRITE_CURRENT_IAC_LAP , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_inquiry_mode (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_inquiry_mode rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.mode = dev->inquiry_mode; +cmd_complete (dev,BT_HCI_CMD_READ_INQUIRY_MODE , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_inquiry_mode (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_write_inquiry_mode *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; + + dev->inquiry_mode = cmd->mode; +cmd_complete (dev,BT_HCI_CMD_WRITE_INQUIRY_MODE , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_page_scan_type (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_page_scan_type rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.type = dev->page_scan_type; +cmd_complete (dev,BT_HCI_CMD_READ_PAGE_SCAN_TYPE , &rsp,sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_page_scan_type (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_write_page_scan_type *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; + + dev->page_scan_type = cmd->type; +cmd_complete (dev,BT_HCI_CMD_WRITE_PAGE_SCAN_TYPE , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_afh_mode (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_read_afh_assessment_mode rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.mode = dev->afh_assessment_mode; +cmd_complete (dev,BT_HCI_CMD_READ_AFH_ASSESSMENT_MODE , &rsp, +sizeof (rsp)); + +return 0 ; +} + +static int cmd_write_afh_mode (struct btdev *dev,const void *data,uint8_t len) +{ +const struct bt_hci_cmd_write_afh_assessment_mode *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; + + dev->afh_assessment_mode = cmd->mode; +cmd_complete (dev,BT_HCI_CMD_WRITE_AFH_ASSESSMENT_MODE , &status, +sizeof (status)); + +return 0 ; +} + +static int cmd_read_local_ext_features (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_local_ext_features rsp; +uint8_t page = ((const uint8_t *) data)[0 ]; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.page = page; + rsp.max_page = dev->max_page; + +if (page > dev->max_page) { + rsp.status =BT_HCI_ERR_INVALID_PARAMETERS ; + goto done; + } + + rsp.status =BT_HCI_ERR_SUCCESS ; + +switch (page) { +case 0x00 : +memcpy (rsp.features, dev->features,8 ); +break ; +case 0x01 : +btdev_get_host_features (dev, rsp.features); +break ; +case 0x02 : +memcpy (rsp.features, dev->feat_page_2,8 ); +break ; +default : + rsp.status =BT_HCI_ERR_INVALID_PARAMETERS ; +break ; + } + +done: +cmd_complete (dev,BT_HCI_CMD_READ_LOCAL_EXT_FEATURES , &rsp, +sizeof (rsp)); + +return 0 ; +} + +static int cmd_read_country_code (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_read_country_code rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.code = dev->country_code; +cmd_complete (dev,BT_HCI_CMD_READ_COUNTRY_CODE , &rsp,sizeof (rsp)); + +return 0 ; } +static int cmd_enable_dut_mode (struct btdev *dev,const void *data, +uint8_t len) +{ +uint8_t status =BT_HCI_ERR_SUCCESS ; + +cmd_complete (dev,BT_HCI_CMD_ENABLE_DUT_MODE , &status, +sizeof (status)); + +return 0 ; +} + +#define CMD_COMMON_BREDR_20 \ + CMD(BT_HCI_CMD_INQUIRY, cmd_inquiry, cmd_inquiry_complete), \ + CMD(BT_HCI_CMD_INQUIRY_CANCEL, cmd_inquiry_cancel, NULL), \ + CMD(BT_HCI_CMD_CREATE_CONN, cmd_create_conn, \ + cmd_create_conn_complete), \ + CMD(BT_HCI_CMD_ADD_SCO_CONN, cmd_add_sco_conn, NULL), \ + CMD(BT_HCI_CMD_CREATE_CONN_CANCEL, cmd_create_conn_cancel, \ + cmd_create_conn_cancel_complete), \ + CMD(BT_HCI_CMD_ACCEPT_CONN_REQUEST, cmd_accept_conn, \ + cmd_accept_conn_complete), \ + CMD(BT_HCI_CMD_REJECT_CONN_REQUEST, cmd_reject_conn, \ + cmd_reject_conn_complete), \ + CMD(BT_HCI_CMD_LINK_KEY_REQUEST_REPLY, cmd_link_key_reply, \ + cmd_link_key_reply_complete), \ + CMD(BT_HCI_CMD_LINK_KEY_REQUEST_NEG_REPLY, \ + cmd_link_key_neg_reply, \ + cmd_link_key_neg_reply_complete), \ + CMD(BT_HCI_CMD_PIN_CODE_REQUEST_REPLY, cmd_pin_code_reply, \ + cmd_pin_code_reply_complete), \ + CMD(BT_HCI_CMD_PIN_CODE_REQUEST_NEG_REPLY, \ + cmd_pin_code_neg_reply, \ + cmd_pin_code_neg_reply_complete), \ + CMD(BT_HCI_CMD_AUTH_REQUESTED, cmd_auth_requested, \ + cmd_auth_requested_complete), \ + CMD(BT_HCI_CMD_SET_CONN_ENCRYPT, cmd_set_conn_encrypt, \ + cmd_set_conn_encrypt_complete), \ + CMD(BT_HCI_CMD_REMOTE_NAME_REQUEST, cmd_remote_name, \ + cmd_remote_name_complete), \ + CMD(BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL, cmd_remote_name_cancel, \ + cmd_remote_name_cancel_complete), \ + CMD(BT_HCI_CMD_READ_REMOTE_FEATURES, cmd_read_remote_features, \ + cmd_read_remote_features_complete), \ + CMD(BT_HCI_CMD_READ_REMOTE_EXT_FEATURES, \ + cmd_read_remote_ext_features, \ + cmd_read_remote_ext_features_compl), \ + CMD(BT_HCI_CMD_READ_CLOCK_OFFSET, cmd_read_clock_offset, \ + cmd_read_clock_offset_complete), \ + CMD(BT_HCI_CMD_READ_DEFAULT_LINK_POLICY, cmd_read_link_policy, NULL), \ + CMD(BT_HCI_CMD_WRITE_DEFAULT_LINK_POLICY, cmd_write_link_policy, \ + NULL), \ + CMD(BT_HCI_CMD_SET_EVENT_FILTER, cmd_set_event_filter, NULL), \ + CMD(BT_HCI_CMD_READ_STORED_LINK_KEY, cmd_read_link_key, NULL), \ + CMD(BT_HCI_CMD_WRITE_STORED_LINK_KEY, cmd_write_link_key, NULL), \ + CMD(BT_HCI_CMD_DELETE_STORED_LINK_KEY, cmd_delete_link_key, NULL), \ + CMD(BT_HCI_CMD_READ_LOCAL_NAME, cmd_read_local_name, NULL), \ + CMD(BT_HCI_CMD_WRITE_LOCAL_NAME, cmd_write_local_name, NULL), \ + CMD(BT_HCI_CMD_READ_CONN_ACCEPT_TIMEOUT, cmd_read_accept_timeout, \ + NULL), \ + CMD(BT_HCI_CMD_WRITE_CONN_ACCEPT_TIMEOUT, cmd_write_accept_timeout, \ + NULL), \ + CMD(BT_HCI_CMD_READ_PAGE_TIMEOUT, cmd_read_page_timeout, NULL), \ + CMD(BT_HCI_CMD_WRITE_PAGE_TIMEOUT, cmd_write_page_timeout, NULL), \ + CMD(BT_HCI_CMD_READ_SCAN_ENABLE, cmd_read_scan_enable, NULL), \ + CMD(BT_HCI_CMD_WRITE_SCAN_ENABLE, cmd_write_scan_enable, NULL), \ + CMD(BT_HCI_CMD_READ_PAGE_SCAN_ACTIVITY, cmd_read_page_scan, NULL), \ + CMD(BT_HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY, cmd_write_page_scan, NULL), \ + CMD(BT_HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY, cmd_read_inquiry_scan, \ + NULL), \ + CMD(BT_HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY, cmd_write_inquiry_scan, \ + NULL), \ + CMD(BT_HCI_CMD_READ_AUTH_ENABLE, cmd_read_auth_enable, NULL), \ + CMD(BT_HCI_CMD_WRITE_AUTH_ENABLE, cmd_write_auth_enable, NULL), \ + CMD(BT_HCI_CMD_READ_CLASS_OF_DEV, cmd_read_class, NULL), \ + CMD(BT_HCI_CMD_WRITE_CLASS_OF_DEV, cmd_write_class, NULL), \ + CMD(BT_HCI_CMD_READ_VOICE_SETTING, cmd_read_voice, NULL), \ + CMD(BT_HCI_CMD_WRITE_VOICE_SETTING, cmd_write_voice, NULL), \ + CMD(BT_HCI_CMD_READ_NUM_SUPPORTED_IAC, cmd_read_num_iac, NULL), \ + CMD(BT_HCI_CMD_READ_CURRENT_IAC_LAP, cmd_read_current_iac_lap, \ + NULL), \ + CMD(BT_HCI_CMD_WRITE_CURRENT_IAC_LAP, cmd_write_current_iac_lap, \ + NULL), \ + CMD(BT_HCI_CMD_READ_INQUIRY_MODE, cmd_read_inquiry_mode, NULL), \ + CMD(BT_HCI_CMD_WRITE_INQUIRY_MODE, cmd_write_inquiry_mode, NULL), \ + CMD(BT_HCI_CMD_READ_PAGE_SCAN_TYPE, cmd_read_page_scan_type, NULL), \ + CMD(BT_HCI_CMD_WRITE_PAGE_SCAN_TYPE, cmd_write_page_scan_type, NULL), \ + CMD(BT_HCI_CMD_READ_AFH_ASSESSMENT_MODE, cmd_read_afh_mode, NULL), \ + CMD(BT_HCI_CMD_WRITE_AFH_ASSESSMENT_MODE, cmd_write_afh_mode, NULL), \ + CMD(BT_HCI_CMD_READ_LOCAL_EXT_FEATURES, cmd_read_local_ext_features, \ + NULL), \ + CMD(BT_HCI_CMD_READ_COUNTRY_CODE, cmd_read_country_code, NULL), \ + CMD(BT_HCI_CMD_ENABLE_DUT_MODE, cmd_enable_dut_mode, NULL) +static void set_common_commands_bredr20 (struct btdev *btdev) { btdev->commands[0 ] |=0x01 ;/* Inquiry */
@@ -334,6 +2116,8 @@ static void set_common_commands_bredr20(struct btdev *btdev) btdev->commands[9 ] |=0x02 ;/* Write Class Of Device */ btdev->commands[9 ] |=0x04 ;/* Read Voice Setting */ btdev->commands[9 ] |=0x08 ;/* Write Voice Setting */ + btdev->commands[11 ] |=0x04 ;/* Read Number of Supported IAC */ + btdev->commands[11 ] |=0x08 ;/* Read Current IAC LAP */ btdev->commands[11 ] |=0x10 ;/* Write Current IAC LAP */ btdev->commands[12 ] |=0x40 ;/* Read Inquiry Mode */ btdev->commands[12 ] |=0x80 ;/* Write Inquiry Mode */
@@ -344,879 +2128,851 @@ static void set_common_commands_bredr20(struct btdev *btdev) btdev->commands[14 ] |=0x40 ;/* Read Local Extended Features */ btdev->commands[15 ] |=0x01 ;/* Read Country Code */ btdev->commands[16 ] |=0x04 ;/* Enable Device Under Test Mode */ -} - -static void set_bredr_commands (struct btdev *btdev) -{ -set_common_commands_all (btdev); -set_common_commands_bredrle (btdev); -set_common_commands_bredr20 (btdev); - - btdev->commands[16 ] |=0x08 ;/* Setup Synchronous Connection */ - btdev->commands[17 ] |=0x01 ;/* Read Extended Inquiry Response */ - btdev->commands[17 ] |=0x02 ;/* Write Extended Inquiry Response */ - btdev->commands[17 ] |=0x20 ;/* Read Simple Pairing Mode */ - btdev->commands[17 ] |=0x40 ;/* Write Simple Pairing Mode */ - btdev->commands[17 ] |=0x80 ;/* Read Local OOB Data */ - btdev->commands[18 ] |=0x01 ;/* Read Inquiry Response TX Power */ - btdev->commands[18 ] |=0x02 ;/* Write Inquiry Response TX Power */ - btdev->commands[18 ] |=0x80 ;/* IO Capability Request Reply */ - btdev->commands[20 ] |=0x10 ;/* Read Encryption Key Size */ - btdev->commands[23 ] |=0x04 ;/* Read Data Block Size */ - btdev->commands[29 ] |=0x20 ;/* Read Local Supported Codecs */ - btdev->commands[30 ] |=0x08 ;/* Get MWS Transport Layer Config */ -} - -static void set_bredr20_commands (struct btdev *btdev) -{ -set_common_commands_all (btdev); -set_common_commands_bredrle (btdev); -set_common_commands_bredr20 (btdev); -} - -static void set_le_50_commands (struct btdev *btdev) -{ - btdev->commands[35 ] |=0x20 ;/* LE Set Default PHY */ - btdev->commands[36 ] |=0x02 ;/* LE Set Adv Set Random Address */ - btdev->commands[36 ] |=0x04 ;/* LE Set Ext Adv Parameters */ - btdev->commands[36 ] |=0x08 ;/* LE Set Ext Adv Data */ - btdev->commands[36 ] |=0x10 ;/* LE Set Ext Scan Response Data */ - btdev->commands[36 ] |=0x20 ;/* LE Set Ext Adv Enable */ - btdev->commands[36 ] |=0x40 ;/* LE Read Maximum Adv Data Length */ - btdev->commands[36 ] |=0x80 ;/* LE Read Num of Supported Adv Sets */ - btdev->commands[37 ] |=0x01 ;/* LE Remove Adv Set */ - btdev->commands[37 ] |=0x02 ;/* LE Clear Adv Sets */ - btdev->commands[37 ] |=0x04 ;/* LE Set Periodic Adv Parameters */ - btdev->commands[37 ] |=0x08 ;/* LE Set Periodic Adv Data */ - btdev->commands[37 ] |=0x10 ;/* LE Set Periodic Adv Enable */ - btdev->commands[37 ] |=0x20 ;/* LE Set Ext Scan Parameters */ - btdev->commands[37 ] |=0x40 ;/* LE Set Ext Scan Enable */ - btdev->commands[37 ] |=0x80 ;/* LE Ext Create Connection */ - btdev->commands[38 ] |=0x01 ;/* LE Periodic Adv Create Sync */ - btdev->commands[38 ] |=0x02 ;/* LE Periodic Adv Create Sync Cancel */ - btdev->commands[38 ] |=0x04 ;/* LE Periodic Adv Terminate Sync */ - btdev->commands[38 ] |=0x08 ;/* LE Add Device To Periodic Adv List */ - btdev->commands[38 ] |=0x10 ;/* LE Remove Periodic Adv List */ - btdev->commands[38 ] |=0x20 ;/* LE Clear Periodic Adv List */ - btdev->commands[38 ] |=0x40 ;/* LE Read Periodic Adv List Size */ -} - -static void set_le_52_commands (struct btdev *btdev) -{ - btdev->commands[41 ] |=0x20 ;/* LE Read Buffer Size v2 */ - btdev->commands[41 ] |=0x40 ;/* LE Read ISO TX Sync */ - btdev->commands[41 ] |=0x80 ;/* LE Set CIG Parameters */ - btdev->commands[42 ] |=0x01 ;/* LE Set CIG Parameters Test */ - btdev->commands[42 ] |=0x02 ;/* LE Create CIS */ - btdev->commands[42 ] |=0x04 ;/* LE Remove CIG */ - btdev->commands[42 ] |=0x08 ;/* LE Accept CIS */ - btdev->commands[42 ] |=0x10 ;/* LE Reject CIS */ - btdev->commands[42 ] |=0x20 ;/* LE Create BIG */ - btdev->commands[42 ] |=0x40 ;/* LE Create BIG Test */ - btdev->commands[42 ] |=0x80 ;/* LE Terminate BIG */ - btdev->commands[43 ] |=0x01 ;/* LE BIG Create Sync */ - btdev->commands[43 ] |=0x02 ;/* LE BIG Terminate Sync */ - btdev->commands[43 ] |=0x04 ;/* LE Request Peer SCA */ - btdev->commands[43 ] |=0x08 ;/* LE Setup ISO Path */ - btdev->commands[43 ] |=0x10 ;/* LE Remove ISO Path */ - btdev->commands[43 ] |=0x20 ;/* LE ISO TX Test */ - btdev->commands[43 ] |=0x40 ;/* LE ISO RX Test */ - btdev->commands[43 ] |=0x80 ;/* LE ISO Read Test Counter */ - btdev->commands[44 ] |=0x01 ;/* LE ISO Test End */ - btdev->commands[44 ] |=0x02 ;/* LE ISO Set Host Feature */ -} - -static void set_le_commands (struct btdev *btdev) -{ -set_common_commands_all (btdev); -set_common_commands_bredrle (btdev); - - btdev->commands[24 ] |=0x20 ;/* Read LE Host Supported */ - btdev->commands[24 ] |=0x20 ;/* Write LE Host Supported */ - btdev->commands[25 ] |=0x01 ;/* LE Set Event Mask */ - btdev->commands[25 ] |=0x02 ;/* LE Read Buffer Size */ - btdev->commands[25 ] |=0x04 ;/* LE Read Local Features */ - btdev->commands[25 ] |=0x10 ;/* LE Set Random Address */ - btdev->commands[25 ] |=0x20 ;/* LE Set Adv Parameters */ - btdev->commands[25 ] |=0x40 ;/* LE Read Adv TX Power */ - btdev->commands[25 ] |=0x80 ;/* LE Set Adv Data */ - btdev->commands[26 ] |=0x01 ;/* LE Set Scan Response Data */ - btdev->commands[26 ] |=0x02 ;/* LE Set Adv Enable */ - btdev->commands[26 ] |=0x04 ;/* LE Set Scan Parameters */ - btdev->commands[26 ] |=0x08 ;/* LE Set Scan Enable */ - btdev->commands[26 ] |=0x10 ;/* LE Create Connection */ - btdev->commands[26 ] |=0x40 ;/* LE Read White List Size */ - btdev->commands[26 ] |=0x80 ;/* LE Clear White List */ - btdev->commands[27 ] |=0x04 ;/* LE Connection Update */ - btdev->commands[27 ] |=0x20 ;/* LE Read Remote Used Features */ - btdev->commands[27 ] |=0x40 ;/* LE Encrypt */ - btdev->commands[27 ] |=0x80 ;/* LE Rand */ - btdev->commands[28 ] |=0x01 ;/* LE Start Encryption */ - btdev->commands[28 ] |=0x02 ;/* LE Long Term Key Request Reply */ - btdev->commands[28 ] |=0x04 ;/* LE Long Term Key Request Neg Reply */ - btdev->commands[28 ] |=0x08 ;/* LE Read Supported States */ - btdev->commands[28 ] |=0x10 ;/* LE Receiver Test */ - btdev->commands[28 ] |=0x20 ;/* LE Transmitter Test */ - btdev->commands[28 ] |=0x40 ;/* LE Test End */ +} -/* Extra LE commands for >= 4.1 adapters */ - btdev->commands[33 ] |=0x10 ;/* LE Remote Conn Param Req Reply */ - btdev->commands[33 ] |=0x20 ;/* LE Remote Conn Param Req Neg Reply */ +static int cmd_setup_sync_conn (struct btdev *dev,const void *data,uint8_t len) +{ +const struct bt_hci_cmd_setup_sync_conn *cmd = data; +struct bt_hci_evt_sync_conn_complete cc; +uint8_t status =BT_HCI_ERR_SUCCESS ; -/* Extra LE commands for >= 4.2 adapters */ - btdev->commands[34 ] |=0x02 ;/* LE Read Local P-256 Public Key */ - btdev->commands[34 ] |=0x04 ;/* LE Generate DHKey */ +cmd_status (dev, status,BT_HCI_EVT_SYNC_CONN_COMPLETE ); -/* Extra LE commands for >= 5.0 adapters */ -if (btdev->type >=BTDEV_TYPE_BREDRLE50 ) -set_le_50_commands (btdev); +if (!dev->conn) +return 0 ; -/* Extra LE commands for >= 5.2 adapters */ -if (btdev->type >=BTDEV_TYPE_BREDRLE52 ) -set_le_52_commands (btdev); -} + cc.status = status; +memcpy (cc.bdaddr, dev->conn->bdaddr,6 ); -static void set_bredrle_commands (struct btdev *btdev) -{ -set_bredr_commands (btdev); -set_le_commands (btdev); + cc.handle =cpu_to_le16 (status ==BT_HCI_ERR_SUCCESS ?SCO_HANDLE :0 ); + cc.link_type =0x02 ; + cc.tx_interval =0x000c ; + cc.retrans_window =0x06 ; + cc.rx_pkt_len =60 ; + cc.tx_pkt_len =60 ; + cc.air_mode = (cmd->voice_setting ==0x0060 ) ?0x02 :0x03 ; -/* Extra BR/EDR commands we want to only support for >= 4.0 -* adapters. -*/ - btdev->commands[22 ] |=0x04 ;/* Set Event Mask Page 2 */ - btdev->commands[31 ] |=0x80 ;/* Read Sync Train Parameters */ - btdev->commands[32 ] |=0x04 ;/* Read Secure Connections Support */ - btdev->commands[32 ] |=0x08 ;/* Write Secure Connections Support */ - btdev->commands[32 ] |=0x10 ;/* Read Auth Payload Timeout */ - btdev->commands[32 ] |=0x20 ;/* Write Auth Payload Timeout */ - btdev->commands[32 ] |=0x40 ;/* Read Local OOB Extended Data */ +send_event (dev,BT_HCI_EVT_SYNC_CONN_COMPLETE , &cc,sizeof (cc)); + +return 0 ; } -static void set_amp_commands (struct btdev *btdev) +static int cmd_read_ext_inquiry (struct btdev *dev,const void *data, +uint8_t len) { -set_common_commands_all (btdev); +struct bt_hci_rsp_read_ext_inquiry_response rsp; - btdev->commands[22 ] |=0x20 ;/* Read Local AMP Info */ +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.fec = dev->ext_inquiry_fec; +memcpy (rsp.data, dev->ext_inquiry_rsp,240 ); +cmd_complete (dev,BT_HCI_CMD_READ_EXT_INQUIRY_RESPONSE , &rsp, +sizeof (rsp)); + +return 0 ; } -static void set_bredrle_features (struct btdev *btdev) +static int cmd_write_ext_inquiry (struct btdev *dev,const void *data, +uint8_t len) { - btdev->features[0 ] |=0x04 ;/* Encryption */ - btdev->features[0 ] |=0x20 ;/* Role switch */ - btdev->features[0 ] |=0x80 ;/* Sniff mode */ - btdev->features[1 ] |=0x08 ;/* SCO link */ - btdev->features[2 ] |=0x08 ;/* Transparent SCO */ - btdev->features[3 ] |=0x40 ;/* RSSI with inquiry results */ - btdev->features[3 ] |=0x80 ;/* Extended SCO link */ - btdev->features[4 ] |=0x08 ;/* AFH capable slave */ - btdev->features[4 ] |=0x10 ;/* AFH classification slave */ - btdev->features[4 ] |=0x40 ;/* LE Supported */ - btdev->features[5 ] |=0x02 ;/* Sniff subrating */ - btdev->features[5 ] |=0x04 ;/* Pause encryption */ - btdev->features[5 ] |=0x08 ;/* AFH capable master */ - btdev->features[5 ] |=0x10 ;/* AFH classification master */ - btdev->features[6 ] |=0x01 ;/* Extended Inquiry Response */ - btdev->features[6 ] |=0x02 ;/* Simultaneous LE and BR/EDR */ - btdev->features[6 ] |=0x08 ;/* Secure Simple Pairing */ - btdev->features[6 ] |=0x10 ;/* Encapsulated PDU */ - btdev->features[6 ] |=0x20 ;/* Erroneous Data Reporting */ - btdev->features[6 ] |=0x40 ;/* Non-flushable Packet Boundary Flag */ - btdev->features[7 ] |=0x01 ;/* Link Supervision Timeout Event */ - btdev->features[7 ] |=0x02 ;/* Inquiry TX Power Level */ - btdev->features[7 ] |=0x80 ;/* Extended features */ +const struct bt_hci_cmd_write_ext_inquiry_response *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; -if (btdev->type >=BTDEV_TYPE_BREDRLE50 ) { -/* These BREDR features are added to test new configuration -* command. If this is added above it will break existing tests -*/ - btdev->features[0 ] |=0x01 ;/* 3 slot Packets */ - btdev->features[0 ] |=0x02 ;/* 5 slot Packets */ - btdev->features[3 ] |=0x02 ;/* EDR ACL 2M mode */ - btdev->features[3 ] |=0x04 ;/* EDR ACL 3M mode */ - btdev->features[4 ] |=0x80 ;/* 3 slot EDR ACL packets */ - btdev->features[5 ] |=0x01 ;/* 5 slot EDR ACL packets */ + dev->ext_inquiry_fec = cmd->fec; +memcpy (dev->ext_inquiry_rsp, cmd->data,240 ); +cmd_complete (dev,BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE , &status, +sizeof (status)); - btdev->le_features[1 ] |=0x01 ;/* LE 2M PHY */ - btdev->le_features[1 ] |=0x08 ;/* LE Coded PHY */ - btdev->le_features[1 ] |=0x10 ;/* LE EXT ADV */ - } +return 0 ; +} -if (btdev->type >=BTDEV_TYPE_BREDRLE52 ) { - btdev->le_features[3 ] |=0x10 ;/* LE CIS Master */ - btdev->le_features[3 ] |=0x20 ;/* LE CIS Slave */ - btdev->le_features[3 ] |=0x40 ;/* LE ISO Broadcaster */ - btdev->le_features[3 ] |=0x80 ;/* LE Synchronized Receiver */ - btdev->le_features[4 ] |=0x01 ;/* LE ISO channels */ - } +static int cmd_read_ssp_mode (struct btdev *dev,const void *data,uint8_t len) +{ +struct bt_hci_rsp_read_simple_pairing_mode rsp; - btdev->feat_page_2[0 ] |=0x01 ;/* CSB - Master Operation */ - btdev->feat_page_2[0 ] |=0x02 ;/* CSB - Slave Operation */ - btdev->feat_page_2[0 ] |=0x04 ;/* Synchronization Train */ - btdev->feat_page_2[0 ] |=0x08 ;/* Synchronization Scan */ - btdev->feat_page_2[0 ] |=0x10 ;/* Inquiry Response Notification */ - btdev->feat_page_2[1 ] |=0x01 ;/* Secure Connections */ - btdev->feat_page_2[1 ] |=0x02 ;/* Ping */ +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.mode = dev->simple_pairing_mode; +cmd_complete (dev,BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE , &rsp, +sizeof (rsp)); - btdev->max_page =2 ; +return 0 ; } -static void set_bredr_features (struct btdev *btdev) +static int cmd_write_ssp_mode (struct btdev *dev,const void *data,uint8_t len) { - btdev->features[0 ] |=0x04 ;/* Encryption */ - btdev->features[0 ] |=0x20 ;/* Role switch */ - btdev->features[0 ] |=0x80 ;/* Sniff mode */ - btdev->features[1 ] |=0x08 ;/* SCO link */ - btdev->features[3 ] |=0x40 ;/* RSSI with inquiry results */ - btdev->features[3 ] |=0x80 ;/* Extended SCO link */ - btdev->features[4 ] |=0x08 ;/* AFH capable slave */ - btdev->features[4 ] |=0x10 ;/* AFH classification slave */ - btdev->features[5 ] |=0x02 ;/* Sniff subrating */ - btdev->features[5 ] |=0x04 ;/* Pause encryption */ - btdev->features[5 ] |=0x08 ;/* AFH capable master */ - btdev->features[5 ] |=0x10 ;/* AFH classification master */ - btdev->features[6 ] |=0x01 ;/* Extended Inquiry Response */ - btdev->features[6 ] |=0x08 ;/* Secure Simple Pairing */ - btdev->features[6 ] |=0x10 ;/* Encapsulated PDU */ - btdev->features[6 ] |=0x20 ;/* Erroneous Data Reporting */ - btdev->features[6 ] |=0x40 ;/* Non-flushable Packet Boundary Flag */ - btdev->features[7 ] |=0x01 ;/* Link Supervision Timeout Event */ - btdev->features[7 ] |=0x02 ;/* Inquiry TX Power Level */ - btdev->features[7 ] |=0x80 ;/* Extended features */ +const struct bt_hci_cmd_write_simple_pairing_mode *cmd = data; +uint8_t status =BT_HCI_ERR_SUCCESS ; - btdev->max_page =1 ; + dev->simple_pairing_mode = cmd->mode; +cmd_complete (dev,BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE , &status, +sizeof (status)); + +return 0 ; } -static void set_bredr20_features (struct btdev *btdev) +static int cmd_read_oob_data (struct btdev *dev,const void *data,uint8_t len) { - btdev->features[0 ] |=0x04 ;/* Encryption */ - btdev->features[0 ] |=0x20 ;/* Role switch */ - btdev->features[0 ] |=0x80 ;/* Sniff mode */ - btdev->features[1 ] |=0x08 ;/* SCO link */ - btdev->features[3 ] |=0x40 ;/* RSSI with inquiry results */ - btdev->features[3 ] |=0x80 ;/* Extended SCO link */ - btdev->features[4 ] |=0x08 ;/* AFH capable slave */ - btdev->features[4 ] |=0x10 ;/* AFH classification slave */ - btdev->features[5 ] |=0x02 ;/* Sniff subrating */ - btdev->features[5 ] |=0x04 ;/* Pause encryption */ - btdev->features[5 ] |=0x08 ;/* AFH capable master */ - btdev->features[5 ] |=0x10 ;/* AFH classification master */ - btdev->features[7 ] |=0x80 ;/* Extended features */ +struct bt_hci_rsp_read_local_oob_data rsp; - btdev->max_page =1 ; +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +cmd_complete (dev,BT_HCI_CMD_READ_LOCAL_OOB_DATA , &rsp,sizeof (rsp)); + +return 0 ; } -static void set_le_features (struct btdev *btdev) +static int cmd_read_inquiry_tx_power (struct btdev *dev,const void *data, +uint8_t len) { - btdev->features[4 ] |=0x20 ;/* BR/EDR Not Supported */ - btdev->features[4 ] |=0x40 ;/* LE Supported */ +struct bt_hci_rsp_read_inquiry_resp_tx_power rsp; - btdev->max_page =1 ; +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.level =0 ; +cmd_complete (dev,BT_HCI_CMD_READ_INQUIRY_RESP_TX_POWER , &rsp, +sizeof (rsp)); - btdev->le_features[0 ] |=0x01 ;/* LE Encryption */ - btdev->le_features[0 ] |=0x02 ;/* Connection Parameters Request */ - btdev->le_features[0 ] |=0x08 ;/* Slave-initiated Features Exchange */ +return 0 ; } -static void set_le_states (struct btdev *btdev) +static int cmd_write_inquiry_tx_power (struct btdev *dev,const void *data, +uint8_t len) { -/* Set all 41 bits as per Bluetooth 5.0 specification */ - btdev->le_states[0 ] =0xff ; - btdev->le_states[1 ] =0xff ; - btdev->le_states[2 ] =0xff ; - btdev->le_states[3 ] =0xff ; - btdev->le_states[4 ] =0xff ; - btdev->le_states[5 ] =0x03 ; +return -ENOTSUP ; } -static void set_amp_features (struct btdev *btdev) +static int cmd_io_cap_reply (struct btdev *dev,const void *data,uint8_t len) { -} +struct btdev *remote = dev->conn; +const struct bt_hci_cmd_io_capability_request_reply *cmd = data; +struct bt_hci_evt_io_capability_response ev; +struct bt_hci_rsp_io_capability_request_reply rsp; +uint8_t status; -struct btdev *btdev_create (enum btdev_type type,uint16_t id) -{ -struct btdev *btdev; -int index; +if (!remote) { + status =BT_HCI_ERR_UNKNOWN_CONN_ID ; + goto done; + } - btdev =malloc (sizeof (*btdev)); -if (!btdev) -return NULL ; + status =BT_HCI_ERR_SUCCESS ; -memset (btdev,0 ,sizeof (*btdev)); + dev->io_cap = cmd->capability; + dev->auth_req = cmd->authentication; -if (type ==BTDEV_TYPE_BREDRLE || type ==BTDEV_TYPE_LE || - type ==BTDEV_TYPE_BREDRLE50 || - type ==BTDEV_TYPE_BREDRLE52 ) { - btdev->crypto =bt_crypto_new (); -if (!btdev->crypto) { -free (btdev); -return NULL ; - } +memcpy (ev.bdaddr, dev->bdaddr,6 ); + ev.capability = cmd->capability; + ev.oob_data = cmd->oob_data; + ev.authentication = cmd->authentication; + +send_event (remote,BT_HCI_EVT_IO_CAPABILITY_RESPONSE , &ev,sizeof (ev)); + +if (remote->io_cap) { +struct bt_hci_evt_user_confirm_request cfm; + +memcpy (cfm.bdaddr, dev->bdaddr,6 ); + cfm.passkey =0 ; + +send_event (remote,BT_HCI_EVT_USER_CONFIRM_REQUEST , + &cfm,sizeof (cfm)); + +memcpy (cfm.bdaddr, cmd->bdaddr,6 ); +send_event (dev,BT_HCI_EVT_USER_CONFIRM_REQUEST , + &cfm,sizeof (cfm)); + }else { +send_event (remote,BT_HCI_EVT_IO_CAPABILITY_REQUEST , + dev->bdaddr,6 ); } - btdev->type = type; +done: + rsp.status = status; +memcpy (rsp.bdaddr, cmd->bdaddr,6 ); +cmd_complete (dev,BT_HCI_CMD_IO_CAPABILITY_REQUEST_REPLY , + &rsp,sizeof (rsp)); - btdev->manufacturer =63 ; - btdev->revision =0x0000 ; +return 0 ; +} -switch (btdev->type) { -case BTDEV_TYPE_BREDRLE : -case BTDEV_TYPE_BREDRLE50 : -case BTDEV_TYPE_BREDRLE52 : - btdev->version =0x09 ; -set_bredrle_features (btdev); -set_bredrle_commands (btdev); -set_le_states (btdev); -break ; -case BTDEV_TYPE_BREDR : - btdev->version =0x05 ; -set_bredr_features (btdev); -set_bredr_commands (btdev); -break ; -case BTDEV_TYPE_LE : - btdev->version =0x09 ; -set_le_features (btdev); -set_le_commands (btdev); -set_le_states (btdev); -break ; -case BTDEV_TYPE_AMP : - btdev->version =0x01 ; -set_amp_features (btdev); -set_amp_commands (btdev); -break ; -case BTDEV_TYPE_BREDR20 : - btdev->version =0x03 ; -set_bredr20_features (btdev); -set_bredr20_commands (btdev); -break ; +static void ssp_complete (struct btdev *btdev,const uint8_t *bdaddr, +uint8_t status,bool wait) +{ +struct bt_hci_evt_simple_pairing_complete iev, aev; +struct bt_hci_evt_auth_complete auth; +struct btdev *remote = btdev->conn; +struct btdev *init, *accp; + +if (!remote) +return ; + + btdev->ssp_status = status; + btdev->ssp_auth_complete = true; + +if (!remote->ssp_auth_complete && wait) +return ; + +if (status ==BT_HCI_ERR_SUCCESS && + remote->ssp_status !=BT_HCI_ERR_SUCCESS ) + status = remote->ssp_status; + + iev.status = status; + aev.status = status; + +if (btdev->auth_init) { + init = btdev; + accp = remote; +memcpy (iev.bdaddr, bdaddr,6 ); +memcpy (aev.bdaddr, btdev->bdaddr,6 ); + }else { + init = remote; + accp = btdev; +memcpy (iev.bdaddr, btdev->bdaddr,6 ); +memcpy (aev.bdaddr, bdaddr,6 ); } - btdev->page_scan_interval =0x0800 ; - btdev->page_scan_window =0x0012 ; - btdev->page_scan_type =0x00 ; +send_event (init,BT_HCI_EVT_SIMPLE_PAIRING_COMPLETE , &iev, +sizeof (iev)); +send_event (accp,BT_HCI_EVT_SIMPLE_PAIRING_COMPLETE , &aev, +sizeof (aev)); - btdev->sync_train_interval =0x0080 ; - btdev->sync_train_timeout =0x0002ee00 ; - btdev->sync_train_service_data =0x00 ; +if (status ==BT_HCI_ERR_SUCCESS ) { +link_key_notify (init, iev.bdaddr,LINK_KEY_DUMMY ); +link_key_notify (accp, aev.bdaddr,LINK_KEY_DUMMY ); + } - btdev->acl_mtu =192 ; - btdev->acl_max_pkt =1 ; + auth.status = status; + auth.handle =cpu_to_le16 (ACL_HANDLE ); +send_event (init,BT_HCI_EVT_AUTH_COMPLETE , &auth,sizeof (auth)); +} - btdev->iso_mtu =251 ; - btdev->iso_max_pkt =1 ; +static int cmd_user_confirm_reply (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_user_confirm_request_reply rsp; - btdev->country_code =0x00 ; +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.bdaddr, data,6 ); +cmd_complete (dev,BT_HCI_CMD_USER_CONFIRM_REQUEST_REPLY , &rsp, +sizeof (rsp)); +ssp_complete (dev, data,BT_HCI_ERR_SUCCESS , true); - index =add_btdev (btdev); -if (index <0 ) { -bt_crypto_unref (btdev->crypto); -free (btdev); -return NULL ; - } +return 0 ; +} -get_bdaddr (id, index, btdev->bdaddr); +static int cmd_user_confirm_negative_reply (struct btdev *dev,const void *data, +uint8_t len) +{ +struct bt_hci_rsp_user_confirm_request_neg_reply rsp; -return btdev; +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.bdaddr, data,6 ); +cmd_complete (dev,BT_HCI_CMD_USER_CONFIRM_REQUEST_NEG_REPLY , + &rsp,sizeof (rsp)); +ssp_complete (dev, data,BT_HCI_ERR_AUTH_FAILURE , true); + +return 0 ; } -void btdev_destroy (struct btdev *btdev) +static int cmd_user_passkey_reply (struct btdev *dev,const void *data, +uint8_t len) { -if (!btdev) -return ; +return -ENOTSUP ; +} -if (btdev->inquiry_id >0 ) -timeout_remove (btdev->inquiry_id); +static int cmd_user_passkey_negative_reply (struct btdev *dev,const void *data, +uint8_t len) +{ +return -ENOTSUP ; +} -bt_crypto_unref (btdev->crypto); -del_btdev (btdev); +static int cmd_io_cap_negative_reply (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_io_capability_request_neg_reply *cmd = data; +struct bt_hci_rsp_io_capability_request_neg_reply rsp; -free (btdev); +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.bdaddr, cmd->bdaddr,6 ); +cmd_complete (dev,BT_HCI_CMD_IO_CAPABILITY_REQUEST_NEG_REPLY , + &rsp,sizeof (rsp)); + +ssp_complete (dev, cmd->bdaddr,BT_HCI_ERR_AUTH_FAILURE , false); + +return 0 ; } -bool btdev_set_debug (struct btdev *btdev,btdev_debug_func_t callback, -void *user_data,btdev_destroy_func_t destroy) +static int cmd_read_encrypt_key_size (struct btdev *dev,const void *data, +uint8_t len) { -if (!btdev) -return false; +const struct bt_hci_cmd_read_encrypt_key_size *cmd = data; +struct bt_hci_rsp_read_encrypt_key_size rsp; -if (btdev->debug_destroy) - btdev->debug_destroy (btdev->debug_data); + rsp.handle = cmd->handle; - btdev->debug_callback = callback; - btdev->debug_destroy = destroy; - btdev->debug_data = user_data; +if (dev->conn) { + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.key_size =16 ; + }else { + rsp.status =BT_HCI_ERR_UNKNOWN_CONN_ID ; + rsp.key_size =0 ; + } -return true; +cmd_complete (dev,BT_HCI_CMD_READ_ENCRYPT_KEY_SIZE , &rsp,sizeof (rsp)); + +return 0 ; } -const uint8_t *btdev_get_bdaddr (struct btdev *btdev) +static int cmd_read_data_block_size (struct btdev *dev,const void *data, +uint8_t len) { -return btdev->bdaddr; +struct bt_hci_rsp_read_data_block_size rsp; + +memset (&rsp,0 ,sizeof (rsp)); + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.max_acl_len =cpu_to_le16 (dev->acl_mtu); + rsp.block_len =cpu_to_le16 (dev->acl_mtu); + rsp.num_blocks =cpu_to_le16 (dev->acl_max_pkt); +cmd_complete (dev,BT_HCI_CMD_READ_DATA_BLOCK_SIZE , &rsp,sizeof (rsp)); + +return 0 ; } -uint8_t *btdev_get_features (struct btdev *btdev) +static int cmd_read_local_codecs (struct btdev *dev,const void *data, +uint8_t len) { -return btdev->features; +struct bt_hci_rsp_read_local_codecs *rsp; + + rsp =alloca (sizeof (*rsp) +7 ); + rsp->status =BT_HCI_ERR_SUCCESS ; + rsp->num_codecs =0x06 ; + rsp->codec[0 ] =0x00 ; + rsp->codec[1 ] =0x01 ; + rsp->codec[2 ] =0x02 ; + rsp->codec[3 ] =0x03 ; + rsp->codec[4 ] =0x04 ; + rsp->codec[5 ] =0x05 ; + rsp->codec[6 ] =0x00 ; +cmd_complete (dev,BT_HCI_CMD_READ_LOCAL_CODECS , rsp,sizeof (*rsp) +7 ); + +return 0 ; } -uint8_t btdev_get_scan_enable (struct btdev *btdev) +static int cmd_get_mws_transport_config (struct btdev *dev,const void *data, +uint8_t len) { -return btdev->scan_enable; +struct bt_hci_rsp_get_mws_transport_config *rsp; + + rsp =alloca (sizeof (*rsp)); + rsp->status =BT_HCI_ERR_SUCCESS ; + rsp->num_transports =0x00 ; +cmd_complete (dev,BT_HCI_CMD_GET_MWS_TRANSPORT_CONFIG , rsp, +sizeof (*rsp)); + +return 0 ; } -uint8_t btdev_get_le_scan_enable (struct btdev *btdev) +#define CMD_BREDR \ + CMD(BT_HCI_CMD_SETUP_SYNC_CONN, cmd_setup_sync_conn, NULL), \ + CMD(BT_HCI_CMD_READ_EXT_INQUIRY_RESPONSE, cmd_read_ext_inquiry, NULL), \ + CMD(BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE, cmd_write_ext_inquiry, \ + NULL), \ + CMD(BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE, cmd_read_ssp_mode, NULL), \ + CMD(BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE, cmd_write_ssp_mode, NULL), \ + CMD(BT_HCI_CMD_READ_LOCAL_OOB_DATA, cmd_read_oob_data, NULL), \ + CMD(BT_HCI_CMD_READ_INQUIRY_RESP_TX_POWER, cmd_read_inquiry_tx_power, \ + NULL), \ + CMD(BT_HCI_CMD_WRITE_INQUIRY_TX_POWER, cmd_write_inquiry_tx_power, \ + NULL), \ + CMD(BT_HCI_CMD_IO_CAPABILITY_REQUEST_REPLY, cmd_io_cap_reply, NULL), \ + CMD(BT_HCI_CMD_USER_CONFIRM_REQUEST_REPLY, cmd_user_confirm_reply, \ + NULL), \ + CMD(BT_HCI_CMD_USER_CONFIRM_REQUEST_NEG_REPLY, \ + cmd_user_confirm_negative_reply, \ + NULL), \ + CMD(BT_HCI_CMD_USER_PASSKEY_REQUEST_NEG_REPLY, cmd_user_passkey_reply, \ + NULL), \ + CMD(BT_HCI_CMD_USER_PASSKEY_REQUEST_NEG_REPLY, \ + cmd_user_passkey_negative_reply, \ + NULL), \ + CMD(BT_HCI_CMD_IO_CAPABILITY_REQUEST_NEG_REPLY, \ + cmd_io_cap_negative_reply, NULL), \ + CMD(BT_HCI_CMD_READ_ENCRYPT_KEY_SIZE, cmd_read_encrypt_key_size, \ + NULL), \ + CMD(BT_HCI_CMD_READ_DATA_BLOCK_SIZE, cmd_read_data_block_size, NULL), \ + CMD(BT_HCI_CMD_READ_LOCAL_CODECS, cmd_read_local_codecs, NULL), \ + CMD(BT_HCI_CMD_GET_MWS_TRANSPORT_CONFIG, cmd_get_mws_transport_config, \ + NULL) + +static const struct btdev_cmd cmd_bredr[] = { +CMD_COMMON_ALL , +CMD_COMMON_BREDR_LE , +CMD_COMMON_BREDR_20 , +CMD_BREDR , + {} +}; + +static void set_bredr_commands (struct btdev *btdev) { -return btdev->le_scan_enable; +set_common_commands_all (btdev); +set_common_commands_bredrle (btdev); +set_common_commands_bredr20 (btdev); + + btdev->commands[16 ] |=0x08 ;/* Setup Synchronous Connection */ + btdev->commands[17 ] |=0x01 ;/* Read Extended Inquiry Response */ + btdev->commands[17 ] |=0x02 ;/* Write Extended Inquiry Response */ + btdev->commands[17 ] |=0x20 ;/* Read Simple Pairing Mode */ + btdev->commands[17 ] |=0x40 ;/* Write Simple Pairing Mode */ + btdev->commands[17 ] |=0x80 ;/* Read Local OOB Data */ + btdev->commands[18 ] |=0x01 ;/* Read Inquiry Response TX Power */ + btdev->commands[18 ] |=0x02 ;/* Write Inquiry Response TX Power */ + btdev->commands[18 ] |=0x80 ;/* IO Capability Request Reply */ + btdev->commands[19 ] |=0x01 ;/* User Confirmation Request Reply */ + btdev->commands[19 ] |=0x02 ;/* User Confirmation Request N Reply */ + btdev->commands[19 ] |=0x04 ;/* User Passkey Request Reply */ + btdev->commands[19 ] |=0x08 ;/* User Passkey Request N Reply */ + btdev->commands[20 ] |=0x08 ;/* IO Capability Request N Reply */ + btdev->commands[20 ] |=0x10 ;/* Read Encryption Key Size */ + btdev->commands[23 ] |=0x04 ;/* Read Data Block Size */ + btdev->commands[29 ] |=0x20 ;/* Read Local Supported Codecs */ + btdev->commands[30 ] |=0x08 ;/* Get MWS Transport Layer Config */ + btdev->cmds = cmd_bredr; } -void btdev_set_le_states (struct btdev *btdev,const uint8_t *le_states) +static const struct btdev_cmd cmd_bredr_20[] = { +CMD_COMMON_ALL , +CMD_COMMON_BREDR_LE , +CMD_COMMON_BREDR_20 , + {} +}; + +static void set_bredr20_commands (struct btdev *btdev) { -memcpy (btdev->le_states, le_states,sizeof (btdev->le_states)); +set_common_commands_all (btdev); +set_common_commands_bredrle (btdev); +set_common_commands_bredr20 (btdev); + btdev->cmds = cmd_bredr_20; } -static bool use_ssp (struct btdev *btdev1,struct btdev *btdev2) +static int cmd_read_le_host_supported (struct btdev *dev,const void *data, +uint8_t len) { -if (btdev1->auth_enable || btdev2->auth_enable) -return false; +struct bt_hci_rsp_read_le_host_supported rsp; -return (btdev1->simple_pairing_mode && btdev2->simple_pairing_mode); +memset (&rsp,0 ,sizeof (rsp)); + + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.supported = dev->le_supported; + rsp.simultaneous = dev->le_simultaneous; +cmd_complete (dev,BT_HCI_CMD_READ_LE_HOST_SUPPORTED , &rsp,sizeof (rsp)); + +return 0 ; } -void btdev_set_command_handler (struct btdev *btdev,btdev_command_func handler, -void *user_data) +static int cmd_write_le_host_supported (struct btdev *dev,const void *data, +uint8_t len) { -if (!btdev) -return ; +const struct bt_hci_cmd_write_le_host_supported *cmd = data; +uint8_t status; - btdev->command_handler = handler; - btdev->command_data = user_data; + dev->le_supported = cmd->supported; + dev->le_simultaneous = cmd->simultaneous; + status =BT_HCI_ERR_SUCCESS ; +cmd_complete (dev,BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED , &status, +sizeof (status)); + +return 0 ; } -void btdev_set_send_handler (struct btdev *btdev,btdev_send_func handler, -void *user_data) +static int cmd_le_set_event_mask (struct btdev *dev,const void *data, +uint8_t len) { -if (!btdev) -return ; +const struct bt_hci_cmd_le_set_event_mask *cmd = data; +uint8_t status; - btdev->send_handler = handler; - btdev->send_data = user_data; +memcpy (dev->le_event_mask, cmd->mask,8 ); + status =BT_HCI_ERR_SUCCESS ; +cmd_complete (dev,BT_HCI_CMD_LE_SET_EVENT_MASK , &status, +sizeof (status)); + +return 0 ; } -static void send_packet (struct btdev *btdev,const struct iovec *iov, -int iovlen) +static int cmd_le_read_buffer_size (struct btdev *dev,const void *data, +uint8_t len) { -int i; +struct bt_hci_rsp_le_read_buffer_size rsp; -if (!btdev->send_handler) -return ; +memset (&rsp,0 ,sizeof (rsp)); -for (i =0 ; i < iovlen; i++) { -if (!i) -util_hexdump ('<' , iov[i].iov_base, iov[i].iov_len, - btdev->debug_callback, btdev->debug_data); -else -util_hexdump (' ' , iov[i].iov_base, iov[i].iov_len, - btdev->debug_callback, btdev->debug_data); - } + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.le_mtu =cpu_to_le16 (dev->acl_mtu); + rsp.le_max_pkt = dev->acl_max_pkt; +cmd_complete (dev,BT_HCI_CMD_LE_READ_BUFFER_SIZE , &rsp,sizeof (rsp)); - btdev->send_handler (iov, iovlen, btdev->send_data); +return 0 ; } -static void send_event (struct btdev *btdev,uint8_t event, -const void *data,uint8_t len) +static int cmd_le_read_local_features (struct btdev *dev,const void *data, +uint8_t len) { -struct bt_hci_evt_hdr hdr; -struct iovec iov[3 ]; -uint8_t pkt =BT_H4_EVT_PKT ; +struct bt_hci_rsp_le_read_local_features rsp; -util_debug (btdev->debug_callback, btdev->debug_data, -"event 0x%02x" , event); +memset (&rsp,0 ,sizeof (rsp)); - iov[0 ].iov_base = &pkt; - iov[0 ].iov_len =sizeof (pkt); + rsp.status =BT_HCI_ERR_SUCCESS ; +memcpy (rsp.features, dev->le_features,8 ); +cmd_complete (dev,BT_HCI_CMD_LE_READ_LOCAL_FEATURES , &rsp,sizeof (rsp)); - hdr.evt = event; - hdr.plen = len; +return 0 ; +} - iov[1 ].iov_base = &hdr; - iov[1 ].iov_len =sizeof (hdr); +static int cmd_set_random_address (struct btdev *dev,const void *data, +uint8_t len) +{ +const struct bt_hci_cmd_le_set_random_address *cmd = data; +uint8_t status; -if (len >0 ) { - iov[2 ].iov_base = (void *) data; - iov[2 ].iov_len = len; - } +memcpy (dev->random_addr, cmd->addr,6 ); + status =BT_HCI_ERR_SUCCESS ; +cmd_complete (dev,BT_HCI_CMD_LE_SET_RANDOM_ADDRESS , &status, +sizeof (status)); -if (run_hooks (btdev,BTDEV_HOOK_POST_EVT , event, data, len)) -send_packet (btdev, iov, len >0 ?3 :2 ); +return 0 ; } -static void send_cmd (struct btdev *btdev,uint8_t evt,uint16_t opcode, -const struct iovec *iov,int iovlen) +static uint16_t ext_legacy_adv_type (uint8_t type) { -struct bt_hci_evt_hdr hdr; -struct iovec iov2[2 + iovlen]; -uint8_t pkt =BT_H4_EVT_PKT ; -int i; +switch (type) { +case 0x00 : +/* Connectable undirected - ADV_IND" */ +return 0x0013 ; +case 0x01 : +/* Connectable directed - ADV_DIRECT_IND */ +return 0x0015 ; +case 0x02 : +/* Scannable undirected - ADV_SCAN_IND */ +return 0x0012 ; +case 0x03 : +/* Non connectable undirected - ADV_NONCONN_IND */ +return 0x0010 ; +case 0x04 : +/* Scan response - SCAN_RSP */ +return 0x0012 ; + } -util_debug (btdev->debug_callback, btdev->debug_data, -"event 0x%02x opcode 0x%04x" , evt, opcode); +return 0x0000 ; +} - iov2[0 ].iov_base = &pkt; - iov2[0 ].iov_len =sizeof (pkt); +static int cmd_set_adv_params (struct btdev *dev,const void *data,uint8_t len) +{ +const struct bt_hci_cmd_le_set_adv_parameters *cmd = data; +uint8_t status; - hdr.evt = evt; - hdr.plen =0 ; +if (dev->le_adv_enable) { + status =BT_HCI_ERR_COMMAND_DISALLOWED ; + goto done; + } - iov2[1 ].iov_base = &hdr; - iov2[1 ].iov_len =sizeof (hdr); + dev->le_adv_type = cmd->type; +/* Use Legacy PDU if the remote is using EXT Scan */ + dev->le_ext_adv_type =ext_legacy_adv_type (cmd->type); + dev->le_adv_own_addr = cmd->own_addr_type; + dev->le_adv_direct_addr_type = cmd->direct_addr_type; +memcpy (dev->le_adv_direct_addr, cmd->direct_addr,6 ); -for (i =0 ; i < iovlen; i++) { - hdr.plen += iov[i].iov_len; - iov2[2 + i].iov_base = iov[i].iov_base; - iov2[2 + i].iov_len = iov[i].iov_len; - } + status =BT_HCI_ERR_SUCCESS ; -if (run_hooks (btdev,BTDEV_HOOK_POST_CMD , opcode, iov[i -1 ].iov_base, - iov[i -1 ].iov_len)) -send_packet (btdev, iov2,2 + iovlen); +done: +cmd_complete (dev,BT_HCI_CMD_LE_SET_ADV_PARAMETERS , &status, +sizeof (status)); + +return 0 ; } -static void cmd_complete (struct btdev *btdev,uint16_t opcode, -const void *data,uint8_t len) +static int cmd_read_adv_tx_power (struct btdev *dev,const void *data, +uint8_t len) { -struct bt_hci_evt_cmd_complete cc; -struct iovec iov[2 ]; - - cc.ncmd =0x01 ; - cc.opcode =cpu_to_le16 (opcode); - - iov[0 ].iov_base = &cc; - iov[0 ].iov_len =sizeof (cc); +struct bt_hci_rsp_le_read_adv_tx_power rsp; - iov[1 ].iov_base = (void *) data; - iov[1 ].iov_len = len; + rsp.status =BT_HCI_ERR_SUCCESS ; + rsp.level =0 ; +cmd_complete (dev,BT_HCI_CMD_LE_READ_ADV_TX_POWER , &rsp,sizeof (rsp)); -send_cmd (btdev,BT_HCI_EVT_CMD_COMPLETE , opcode, iov,2 ); +return 0 ; } -static void cmd_status (struct btdev *btdev,uint8_t status,uint16_t opcode) +static int cmd_set_adv_data (struct btdev *dev,const void *data,uint8_t len) { -struct bt_hci_evt_cmd_status cs; -struct iovec iov; +const struct bt_hci_cmd_le_set_adv_data *cmd = data; +uint8_t status; - cs.status = status; - cs.ncmd =0x01 ; - cs.opcode =cpu_to_le16 (opcode); + dev->le_adv_data_len = cmd->len; +memcpy (dev->le_adv_data, cmd->data,31 ); + status =BT_HCI_ERR_SUCCESS ; - iov.iov_base = &cs; - iov.iov_len =sizeof (cs); +cmd_complete (dev,BT_HCI_CMD_LE_SET_ADV_DATA , &status,sizeof (status)); -send_cmd (btdev,BT_HCI_EVT_CMD_STATUS , opcode, &iov,1 ); +return 0 ; } -static void le_meta_event (struct btdev *btdev,uint8_t event, -void *data,uint8_t len) +static int cmd_set_scan_rsp_data (struct btdev *dev,const void *data, +uint8_t len) { -void *pkt_data; +const struct bt_hci_cmd_le_set_scan_rsp_data *cmd = data; +uint8_t status; -util_debug (btdev->debug_callback, btdev->debug_data, -"meta event 0x%02x" , event); + dev->le_scan_data_len = cmd->len; +memcpy (dev->le_scan_data, cmd->data,31 ); + status =BT_HCI_ERR_SUCCESS ; +cmd_complete (dev,BT_HCI_CMD_LE_SET_SCAN_RSP_DATA , &status, +sizeof (status)); - pkt_data =alloca (1 + len); -if (!pkt_data) -return ; +return 0 ; +} - ((uint8_t *) pkt_data)[0 ] = event; +static uint8_t get_ext_adv_type (uint8_t ext_adv_type) +{ +/* +* If legacy bit is not set then just reset high duty cycle directed +* bit. +*/ +if (!(ext_adv_type &0x10 )) +return (ext_adv_type &0xf7 ); -if (len >0 ) -memcpy (pkt_data +1 , data, len); +/* +* Connectable low duty cycle directed advertising creates a +* connectable directed advertising report type. +*/ +if (ext_adv_type ==0x001d ) +return 0x0015 ; -send_event (btdev,BT_HCI_EVT_LE_META_EVENT , pkt_data,1 + len); +return ext_adv_type; } -static void num_completed_packets (struct btdev *btdev,uint16_t handle) +static const uint8_t *scan_addr (const struct btdev *btdev) { -if (btdev->conn) { -struct bt_hci_evt_num_completed_packets ncp; - - ncp.num_handles =1 ; - ncp.handle =cpu_to_le16 (handle); - ncp.count =cpu_to_le16 (1 ); +if (btdev->le_scan_own_addr_type ==0x01 ) +return btdev->random_addr; -send_event (btdev,BT_HCI_EVT_NUM_COMPLETED_PACKETS , - &ncp,sizeof (ncp)); - } +return btdev->bdaddr; } -static bool inquiry_callback (void *user_data) +static bool ext_adv_match (struct btdev *scan,struct btdev *adv) { -struct inquiry_data *data = user_data; -struct btdev *btdev = data->btdev; -struct bt_hci_evt_inquiry_complete ic; -int sent = data->sent_count; -int i; - -/*Report devices only once and wait for inquiry timeout*/ -if (data->iter ==MAX_BTDEV_ENTRIES ) +/* Match everything if this is not directed advertising */ +if (!(adv->le_ext_adv_type &0x04 ))return true; -for (i = data->iter; i <MAX_BTDEV_ENTRIES ; i++) { -/*Lets sent 10 inquiry results at once */ -if (sent +10 == data->sent_count) -break ; - -if (!btdev_list[i] || btdev_list[i] == btdev) -continue ; - -if (!(btdev_list[i]->scan_enable &0x02 )) -continue ; - -if (btdev->inquiry_mode ==0x02 && - btdev_list[i]->ext_inquiry_rsp[0 ]) { -struct bt_hci_evt_ext_inquiry_result ir; +if (scan->le_scan_own_addr_type != adv->le_adv_direct_addr_type) +return false; - ir.num_resp =0x01 ; -memcpy (ir.bdaddr, btdev_list[i]->bdaddr,6 ); - ir.pscan_rep_mode =0x00 ; - ir.pscan_period_mode =0x00 ; -memcpy (ir.dev_class, btdev_list[i]->dev_class,3 ); - ir.clock_offset =0x0000 ; - ir.rssi =-60 ; -memcpy (ir.data, btdev_list[i]->ext_inquiry_rsp,240 ); +return !memcmp (scan_addr (scan), adv->le_adv_direct_addr,6 ); +} -send_event (btdev,BT_HCI_EVT_EXT_INQUIRY_RESULT , - &ir,sizeof (ir)); - data->sent_count++; -continue ; - } +static const uint8_t *adv_addr (const struct btdev *btdev) +{ +if (btdev->le_adv_own_addr ==0x01 ) +return btdev->random_addr; -if (btdev->inquiry_mode >0x00 ) { -struct bt_hci_evt_inquiry_result_with_rssi ir; +return btdev->bdaddr; +} - ir.num_resp =0x01 ;
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.26.2
Part of the diff is not shown here. View the raw message.
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list. This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=381525
---Test result---
##############################
Test: CheckPatch - FAIL
Output:
emulator: Rework command handling
ERROR:SPACING: need consistent spacing around '-' (ctx:WxV) #100: FILE: emulator/btdev.c:336:
+ if (run_hooks(btdev, BTDEV_HOOK_POST_CMD, opcode, iov[i -1].iov_base,
^
ERROR:SPACING: need consistent spacing around '-' (ctx:WxV) #101: FILE: emulator/btdev.c:337:
+ iov[i -1].iov_len))
^
- total: 2 errors, 0 warnings, 7681 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
"[PATCH] emulator: Rework command handling" has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: CheckGitLint - PASS
##############################
Test: CheckBuild - PASS
##############################
Test: MakeCheck - PASS
---
Regards,
Linux Bluetooth