#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
+#include <time.h>
#include "lib/bluetooth.h"
#include "lib/hci.h"
struct bt_phy *phy;
struct bt_crypto *crypto;
int adv_timeout_id;
+ int scan_timeout_id;
+ bool scan_window_active;
+ uint8_t scan_chan_idx;
uint8_t event_mask[16];
uint16_t manufacturer;
fprintf(stderr, "Write to /dev/vhci failed (%m)\n");
}
-static void send_adv_pkt(struct bt_le *hci)
+static void send_adv_pkt(struct bt_le *hci, uint8_t channel)
{
struct bt_phy_pkt_adv pkt;
memset(&pkt, 0, sizeof(pkt));
+ pkt.chan_idx = channel;
pkt.pdu_type = hci->le_adv_type;
pkt.tx_addr_type = hci->le_adv_own_addr_type;
switch (hci->le_adv_own_addr_type) {
hci->le_scan_rsp_data, pkt.scan_rsp_len);
}
+static unsigned int get_adv_delay(void)
+{
+ /* The advertising delay is a pseudo-random value with a range
+ * of 0 ms to 10 ms generated for each advertising event.
+ */
+ srand(time(NULL));
+ return (rand() % 11);
+}
+
static void adv_timeout_callback(int id, void *user_data)
{
struct bt_le *hci = user_data;
- unsigned int min_msec, max_msec;
+ unsigned int msec, min_msec, max_msec;
- send_adv_pkt(hci);
+ if (hci->le_adv_channel_map & 0x01)
+ send_adv_pkt(hci, 37);
+ if (hci->le_adv_channel_map & 0x02)
+ send_adv_pkt(hci, 38);
+ if (hci->le_adv_channel_map & 0x04)
+ send_adv_pkt(hci, 39);
min_msec = (hci->le_adv_min_interval * 625) / 1000;
max_msec = (hci->le_adv_max_interval * 625) / 1000;
- if (mainloop_modify_timeout(id, (min_msec + max_msec) / 2) < 0) {
+ msec = ((min_msec + max_msec) / 2) + get_adv_delay();
+
+ if (mainloop_modify_timeout(id, msec) < 0) {
fprintf(stderr, "Setting advertising timeout failed\n");
hci->le_adv_enable = 0x00;
}
if (hci->adv_timeout_id >= 0)
return false;
- msec = (hci->le_adv_min_interval * 625) / 1000;
+ msec = ((hci->le_adv_min_interval * 625) / 1000) + get_adv_delay();
hci->adv_timeout_id = mainloop_add_timeout(msec, adv_timeout_callback,
hci, NULL);
return true;
}
+static void scan_timeout_callback(int id, void *user_data)
+{
+ struct bt_le *hci = user_data;
+ unsigned int msec;
+
+ if (hci->le_scan_window == hci->le_scan_interval ||
+ !hci->scan_window_active) {
+ msec = (hci->le_scan_window * 625) / 1000;
+ hci->scan_window_active = true;
+
+ hci->scan_chan_idx++;
+ if (hci->scan_chan_idx > 39)
+ hci->scan_chan_idx = 37;
+ } else {
+ msec = ((hci->le_scan_interval -
+ hci->le_scan_window) * 625) / 1000;
+ hci->scan_window_active = false;
+ }
+
+ if (mainloop_modify_timeout(id, msec) < 0) {
+ fprintf(stderr, "Setting scanning timeout failed\n");
+ hci->le_scan_enable = 0x00;
+ hci->scan_window_active = false;
+ }
+}
+
+static bool start_scan(struct bt_le *hci)
+{
+ unsigned int msec;
+
+ if (hci->scan_timeout_id >= 0)
+ return false;
+
+ msec = (hci->le_scan_window * 625) / 1000;
+
+ hci->scan_timeout_id = mainloop_add_timeout(msec, scan_timeout_callback,
+ hci, NULL);
+ if (hci->scan_timeout_id < 0)
+ return false;
+
+ hci->scan_window_active = true;
+ hci->scan_chan_idx = 37;
+
+ return true;
+}
+
+static bool stop_scan(struct bt_le *hci)
+{
+ if (hci->scan_timeout_id < 0)
+ return false;
+
+ mainloop_remove_timeout(hci->scan_timeout_id);
+ hci->scan_timeout_id = -1;
+
+ hci->scan_window_active = false;
+
+ return true;
+}
+
static void cmd_complete(struct bt_le *hci, uint16_t opcode,
const void *data, uint8_t len)
{
uint8_t status;
stop_adv(hci);
+ stop_scan(hci);
reset_defaults(hci);
status = BT_HCI_ERR_SUCCESS;
{
const struct bt_hci_cmd_le_set_scan_enable *cmd = data;
uint8_t status;
+ bool result;
/* Valid range for scan enable is 0x00 to 0x01 */
if (cmd->enable > 0x01) {
clear_scan_cache(hci);
+ if (cmd->enable == 0x01)
+ result = start_scan(hci);
+ else
+ result = stop_scan(hci);
+
+ if (!result) {
+ cmd_status(hci, BT_HCI_ERR_UNSPECIFIED_ERROR,
+ BT_HCI_CMD_LE_SET_SCAN_ENABLE);
+ return;
+ }
+
hci->le_scan_enable = cmd->enable;
hci->le_scan_filter_dup = cmd->filter_dup;
if (!(hci->le_event_mask[0] & 0x02))
return;
- if (hci->le_scan_enable == 0x01) {
+ if (hci->scan_window_active) {
const struct bt_phy_pkt_adv *pkt = data;
uint8_t buf[100];
struct bt_hci_evt_le_adv_report *evt = (void *) buf;
uint8_t tx_addr_type, tx_addr[6];
+ if (hci->scan_chan_idx != pkt->chan_idx)
+ break;
+
resolve_peer_addr(hci, pkt->tx_addr_type, pkt->tx_addr,
&tx_addr_type, tx_addr);
return NULL;
hci->adv_timeout_id = -1;
+ hci->scan_timeout_id = -1;
+ hci->scan_window_active = false;
reset_defaults(hci);