int bt_le_set_auto_conn(bt_addr_le_t *addr, const struct bt_le_conn_param *param) { struct bt_conn *conn; if (param && !bt_le_conn_params_valid(param->interval_min, param->interval_max, param->latency, param->timeout)) { return -EINVAL; } conn = bt_conn_lookup_addr_le(addr); if (!conn) { conn = bt_conn_add_le(addr); if (!conn) { return -ENOMEM; } } if (param) { bt_conn_set_param_le(conn, param); if (!atomic_test_and_set_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { bt_conn_ref(conn); } } else { if (atomic_test_and_clear_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { bt_conn_unref(conn); if (conn->state == BT_CONN_CONNECT_SCAN) { bt_conn_set_state(conn, BT_CONN_DISCONNECTED); } } } if (conn->state == BT_CONN_DISCONNECTED && atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { if (param) { bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); } bt_le_scan_update(false); } bt_conn_unref(conn); return 0; }
void on_nble_gap_disconnect_evt(const struct nble_gap_disconnect_evt *evt) { struct bt_conn *conn; #if 0 /* Nordic has no disconnection error */ if (evt->status) { return; } #endif conn = bt_conn_lookup_handle(evt->conn_handle); if (!conn) { BT_DBG("Unable to look up conn with handle %u", evt->conn_handle); return; } #if 0 /* Check stacks usage (no-ops if not enabled) */ stack_analyze("rx stack", rx_fiber_stack, sizeof(rx_fiber_stack)); stack_analyze("cmd rx stack", rx_prio_fiber_stack, sizeof(rx_prio_fiber_stack)); stack_analyze("cmd tx stack", cmd_tx_fiber_stack, sizeof(cmd_tx_fiber_stack)); stack_analyze("conn tx stack", conn->stack, sizeof(conn->stack)); #endif conn->err = evt->hci_reason; bt_conn_set_state(conn, BT_CONN_DISCONNECTED); conn->handle = 0; #if 0 /* Only LE supported */ if (conn->type != BT_CONN_TYPE_LE) { bt_conn_unref(conn); return; } /* TODO enabled when autoconn is supported */ if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); bt_le_scan_update(false); } #endif bt_conn_unref(conn); if (atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING)) { set_advertise_enable(); } }
int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason) { #if defined(CONFIG_BLUETOOTH_CENTRAL) /* Disconnection is initiated by us, so auto connection shall * be disabled. Otherwise the passive scan would be enabled * and we could send LE Create Connection as soon as the remote * starts advertising. */ if (conn->type == BT_CONN_TYPE_LE) { bt_le_set_auto_conn(&conn->le.dst, NULL); } #endif switch (conn->state) { case BT_CONN_CONNECT_SCAN: bt_conn_set_state(conn, BT_CONN_DISCONNECTED); bt_le_scan_update(false); return 0; case BT_CONN_CONNECT: #if defined(CONFIG_BLUETOOTH_BREDR) if (conn->type == BT_CONN_TYPE_BR) { return bt_hci_connect_br_cancel(conn); } #endif /* CONFIG_BLUETOOTH_BREDR */ return bt_hci_connect_le_cancel(conn); case BT_CONN_CONNECTED: return bt_hci_disconnect(conn, reason); case BT_CONN_DISCONNECT: return 0; case BT_CONN_DISCONNECTED: default: return -ENOTCONN; } }
void on_nble_gap_dir_adv_timeout_evt(const struct nble_gap_dir_adv_timeout_evt *p_evt) { struct bt_conn *conn = bt_conn_lookup_state_le(BT_ADDR_LE_ANY, BT_CONN_CONNECT); if (conn) { atomic_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING); conn->err = p_evt->error; bt_conn_set_state(conn, BT_CONN_DISCONNECTED); bt_conn_unref(conn); } }
struct bt_conn *bt_conn_create_br(const bt_addr_t *peer, const struct bt_br_conn_param *param) { struct bt_hci_cp_connect *cp; struct bt_conn *conn; struct net_buf *buf; conn = bt_conn_lookup_addr_br(peer); if (conn) { switch (conn->state) { return conn; case BT_CONN_CONNECT: case BT_CONN_CONNECTED: return conn; default: bt_conn_unref(conn); return NULL; } } conn = bt_conn_add_br(peer); if (!conn) { return NULL; } buf = bt_hci_cmd_create(BT_HCI_OP_CONNECT, sizeof(*cp)); if (!buf) { bt_conn_unref(conn); return NULL; } cp = net_buf_add(buf, sizeof(*cp)); memset(cp, 0, sizeof(*cp)); memcpy(&cp->bdaddr, peer, sizeof(cp->bdaddr)); cp->packet_type = sys_cpu_to_le16(0xcc18); /* DM1 DH1 DM3 DH5 DM5 DH5 */ cp->pscan_rep_mode = 0x02; /* R2 */ cp->allow_role_switch = param->allow_role_switch ? 0x01 : 0x00; cp->clock_offset = 0x0000; /* TODO used cached clock offset */ if (bt_hci_cmd_send_sync(BT_HCI_OP_CONNECT, buf, NULL) < 0) { bt_conn_unref(conn); return NULL; } bt_conn_set_state(conn, BT_CONN_CONNECT); conn->role = BT_CONN_ROLE_MASTER; return conn; }
static void background_scan_init(void) { #if defined(CONFIG_BLUETOOTH_CENTRAL) int i; for (i = 0; i < ARRAY_SIZE(conns); i++) { struct bt_conn *conn = &conns[i]; if (!atomic_get(&conn->ref)) { continue; } if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); } } #endif /* CONFIG_BLUETOOTH_CENTRAL */ }
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, const struct bt_le_conn_param *param) { struct bt_conn *conn; if (!bt_le_conn_params_valid(param->interval_min, param->interval_max, param->latency, param->timeout)) { return NULL; } if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) { return NULL; } conn = bt_conn_lookup_addr_le(peer); if (conn) { switch (conn->state) { case BT_CONN_CONNECT_SCAN: bt_conn_set_param_le(conn, param); return conn; case BT_CONN_CONNECT: case BT_CONN_CONNECTED: return conn; default: bt_conn_unref(conn); return NULL; } } conn = bt_conn_add_le(peer); if (!conn) { return NULL; } bt_conn_set_param_le(conn, param); bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); bt_le_scan_update(true); return conn; }
static int bt_hci_disconnect(struct bt_conn *conn, uint8_t reason) { struct net_buf *buf; struct bt_hci_cp_disconnect *disconn; int err; buf = bt_hci_cmd_create(BT_HCI_OP_DISCONNECT, sizeof(*disconn)); if (!buf) { return -ENOBUFS; } disconn = net_buf_add(buf, sizeof(*disconn)); disconn->handle = sys_cpu_to_le16(conn->handle); disconn->reason = reason; err = bt_hci_cmd_send(BT_HCI_OP_DISCONNECT, buf); if (err) { return err; } bt_conn_set_state(conn, BT_CONN_DISCONNECT); return 0; }
void on_nble_gap_connect_evt(const struct nble_gap_connect_evt *evt) { struct bt_conn *conn; /* Make lookup to check if there's a connection object in CONNECT state * associated with passed peer LE address. */ conn = bt_conn_lookup_state_le(&evt->peer_bda, BT_CONN_CONNECT); #if 0 /* Nordic has no connection error */ if (evt->status) { if (!conn) { return; } conn->err = BT_HCI_ERR_UNACCEPT_CONN_PARAMS; bt_conn_set_state(conn, BT_CONN_DISCONNECTED); /* Drop the reference got by lookup call in CONNECT state. * We are now in DISCONNECTED state since no successful LE * link been made. */ bt_conn_unref(conn); return; } #endif /* * clear advertising even if we are not able to add connection object * to keep host in sync with controller state */ if (evt->role_slave == BT_CONN_ROLE_SLAVE) { atomic_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING); } if (!conn) { conn = bt_conn_add_le(&evt->peer_bda); } if (!conn) { BT_DBG("Unable to add new conn for handle %u", evt->conn_handle); return; } conn->handle = evt->conn_handle; bt_addr_le_copy(&conn->le.dst, &evt->peer_bda); conn->le.interval = evt->conn_values.interval; conn->le.latency = evt->conn_values.latency; conn->le.timeout = evt->conn_values.supervision_to; conn->role = evt->role_slave; #if 0 src.type = BT_ADDR_LE_PUBLIC; memcpy(src.val, bt_dev.bdaddr.val, sizeof(bt_dev.bdaddr.val)); /* use connection address (instead of identity address) as initiator * or responder address */ if (conn->role == BT_HCI_ROLE_MASTER) { bt_addr_le_copy(&conn->le.init_addr, &src); bt_addr_le_copy(&conn->le.resp_addr, &evt->peer_addr); } else { bt_addr_le_copy(&conn->le.init_addr, &evt->peer_addr); bt_addr_le_copy(&conn->le.resp_addr, &src); } #endif bt_conn_set_state(conn, BT_CONN_CONNECTED); /* Note: Connection update removed because Windows interop and BT spec recommendations */ bt_conn_unref(conn); #if 0 bt_le_scan_update(false); #endif }