static int unprovisioned_beacon_send(void) { #if defined(CONFIG_BT_MESH_PB_ADV) const struct bt_mesh_prov *prov; struct net_buf *buf; u8_t uri_hash[16] = { 0 }; u16_t oob_info; BT_DBG(""); buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, UNPROV_XMIT_COUNT, UNPROV_XMIT_INT, K_NO_WAIT); if (!buf) { BT_ERR("Unable to allocate beacon buffer"); return -ENOBUFS; } prov = bt_mesh_prov_get(); net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED); net_buf_add_mem(buf, prov->uuid, 16); /* for tmall ble profile, OOB info default is 0x0000 URI hash is optional */ if (prov->uri && bt_mesh_s1(prov->uri, uri_hash) == 0) { oob_info = prov->oob_info | BT_MESH_PROV_OOB_URI; } else { oob_info = prov->oob_info; } net_buf_add_be16(buf, oob_info); net_buf_add_mem(buf, uri_hash, 4); bt_mesh_adv_send(buf, NULL, NULL); net_buf_unref(buf); if (prov->uri) { size_t len; buf = bt_mesh_adv_create(BT_MESH_ADV_URI, UNPROV_XMIT_COUNT, UNPROV_XMIT_INT, K_NO_WAIT); if (!buf) { BT_ERR("Unable to allocate URI buffer"); return -ENOBUFS; } len = strlen(prov->uri); if (net_buf_tailroom(buf) < len) { BT_WARN("Too long URI to fit advertising data"); } else { net_buf_add_mem(buf, prov->uri, len); bt_mesh_adv_send(buf, NULL, NULL); } net_buf_unref(buf); } #endif /* CONFIG_BT_MESH_PB_ADV */ return 0; }
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf) { struct bt_l2cap_hdr *hdr = (void *)buf->data; struct bt_l2cap_chan *chan; uint16_t cid; if (IS_ENABLED(CONFIG_BLUETOOTH_BREDR) && conn->type == BT_CONN_TYPE_BR) { bt_l2cap_br_recv(conn, buf); return; } if (buf->len < sizeof(*hdr)) { BT_ERR("Too small L2CAP PDU received"); net_buf_unref(buf); return; } cid = sys_le16_to_cpu(hdr->cid); net_buf_pull(buf, sizeof(*hdr)); BT_DBG("Packet for CID %u len %u", cid, buf->len); chan = bt_l2cap_le_lookup_rx_cid(conn, cid); if (!chan) { BT_WARN("Ignoring data for unknown CID 0x%04x", cid); net_buf_unref(buf); return; } l2cap_chan_recv(chan, buf); net_buf_unref(buf); }
int bt_conn_auth_pincode_entry(struct bt_conn *conn, const char *pin) { size_t len; if (!bt_auth) { return -EINVAL; } if (conn->type != BT_CONN_TYPE_BR) { return -EINVAL; } len = strlen(pin); if (len > 16) { return -EINVAL; } if (conn->required_sec_level == BT_SECURITY_HIGH && len < 16) { BT_WARN("PIN code for %s is not 16 bytes wide", bt_addr_str(&conn->br.dst)); return -EPERM; } /* Allow user send entered PIN to remote, then reset user state. */ if (!atomic_test_and_clear_bit(conn->flags, BT_CONN_USER)) { return -EPERM; } if (len == 16) { atomic_set_bit(conn->flags, BT_CONN_BR_LEGACY_SECURE); } return pin_code_reply(conn, pin, len); }
void on_nble_gap_start_advertise_rsp(const struct nble_response *params) { if (params->status == 0) atomic_set_bit(bt_dev.flags, BT_DEV_ADVERTISING); else BT_WARN("start advertise failed with %d", params->status); }
struct net_buf *bt_att_create_pdu(struct bt_conn *conn, uint8_t op, size_t len) { struct bt_att_hdr *hdr; struct net_buf *buf; struct bt_att *att; att = att_chan_get(conn); if (!att) { return NULL; } if (len + sizeof(op) > att->chan.tx.mtu) { BT_WARN("ATT MTU exceeded, max %u, wanted %zu", att->chan.tx.mtu, len + sizeof(op)); return NULL; } buf = bt_l2cap_create_pdu(&att_buf); if (!buf) { return NULL; } hdr = net_buf_add(buf, sizeof(*hdr)); hdr->code = op; return buf; }
static int storage_init(struct device *unused) { static const struct bt_storage storage = { .read = storage_read, .write = storage_write, .clear = storage_clear }; struct fs_dirent entry; int err; err = fs_stat(STORAGE_ROOT, &entry); if (err) { BT_WARN("%s doesn't seem to exist (err %d). Creating it.", STORAGE_ROOT, err); err = fs_mkdir(STORAGE_ROOT); if (err) { BT_ERR("Unable to create %s (err %d)", STORAGE_ROOT, err); return err; } } bt_storage_register(&storage); return 0; }
int bt_gatt_attr_write_ccc(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset) { struct _bt_gatt_ccc *ccc = attr->user_data; const uint16_t *data = buf; bool bonded; size_t i; if (offset > sizeof(*data)) { return -EINVAL; } if (offset + len > sizeof(*data)) { return -EFBIG; } if (bt_keys_find_addr(&conn->le.dst)) bonded = true; else bonded = false; for (i = 0; i < ccc->cfg_len; i++) { /* Check for existing configuration */ if (!bt_addr_le_cmp(&ccc->cfg[i].peer, &conn->le.dst)) { break; } } if (i == ccc->cfg_len) { for (i = 0; i < ccc->cfg_len; i++) { /* Check for unused configuration */ if (!ccc->cfg[i].valid) { bt_addr_le_copy(&ccc->cfg[i].peer, &conn->le.dst); /* Only set valid if bonded */ ccc->cfg[i].valid = bonded; break; } } if (i == ccc->cfg_len) { BT_WARN("No space to store CCC cfg"); return -ENOMEM; } } ccc->cfg[i].value = sys_le16_to_cpu(*data); BT_DBG("handle 0x%04x value %u", attr->handle, ccc->cfg[i].value); /* Update cfg if don't match */ if (ccc->cfg[i].value != ccc->value) { gatt_ccc_changed(ccc); } return len; }
void bt_l2cap_chan_set_state_debug(struct bt_l2cap_chan *chan, bt_l2cap_chan_state_t state, const char *func, int line) { BT_DBG("chan %p psm 0x%04x %s -> %s", chan, chan->psm, bt_l2cap_chan_state_str(chan->state), bt_l2cap_chan_state_str(state)); /* check transitions validness */ switch (state) { case BT_L2CAP_DISCONNECTED: /* regardless of old state always allows this state */ break; case BT_L2CAP_CONNECT: if (chan->state != BT_L2CAP_DISCONNECTED) { BT_WARN("%s()%d: invalid transition", func, line); } break; case BT_L2CAP_CONFIG: if (chan->state != BT_L2CAP_CONNECT) { BT_WARN("%s()%d: invalid transition", func, line); } break; case BT_L2CAP_CONNECTED: if (chan->state != BT_L2CAP_CONFIG && chan->state != BT_L2CAP_CONNECT) { BT_WARN("%s()%d: invalid transition", func, line); } break; case BT_L2CAP_DISCONNECT: if (chan->state != BT_L2CAP_CONFIG && chan->state != BT_L2CAP_CONNECTED) { BT_WARN("%s()%d: invalid transition", func, line); } break; default: BT_ERR("%s()%d: unknown (%u) state was set", func, line, state); return; } chan->state = state; }
static struct net_buf *l2cap_chan_create_seg(struct bt_l2cap_le_chan *ch, struct net_buf *buf, size_t sdu_hdr_len) { struct net_buf *seg; uint16_t headroom; uint16_t len; /* Segment if data (+ data headroom) is bigger than MPS */ if (buf->len + sdu_hdr_len > ch->tx.mps) { goto segment; } /* Segment if there is no space in the user_data */ if (buf->pool->user_data_size < BT_BUF_USER_DATA_MIN) { BT_WARN("Too small buffer user_data_size %u", buf->pool->user_data_size); goto segment; } headroom = sizeof(struct bt_hci_acl_hdr) + sizeof(struct bt_l2cap_hdr) + sdu_hdr_len; /* Check if original buffer has enough headroom and don't have any * fragments. */ if (net_buf_headroom(buf) >= headroom && !buf->frags) { if (sdu_hdr_len) { /* Push SDU length if set */ net_buf_push_le16(buf, net_buf_frags_len(buf)); } return net_buf_ref(buf); } segment: seg = bt_l2cap_create_pdu(&le_data_pool, 0); if (sdu_hdr_len) { net_buf_add_le16(seg, net_buf_frags_len(buf)); } /* Don't send more that TX MPS including SDU length */ len = min(net_buf_tailroom(seg), ch->tx.mps - sdu_hdr_len); /* Limit if original buffer is smaller than the segment */ len = min(buf->len, len); net_buf_add_mem(seg, buf->data, len); net_buf_pull(buf, len); BT_DBG("ch %p seg %p len %u", ch, seg, seg->len); return seg; }
static inline void process_tx(void) { int bytes; if (!tx.buf) { tx.buf = net_buf_get(&tx.fifo, K_NO_WAIT); if (!tx.buf) { BT_ERR("TX interrupt but no pending buffer!"); uart_irq_tx_disable(h4_dev); return; } } if (!tx.type) { switch (bt_buf_get_type(tx.buf)) { case BT_BUF_ACL_OUT: tx.type = H4_ACL; break; case BT_BUF_CMD: tx.type = H4_CMD; break; default: BT_ERR("Unknown buffer type"); goto done; } bytes = uart_fifo_fill(h4_dev, &tx.type, 1); if (bytes != 1) { BT_WARN("Unable to send H:4 type"); tx.type = H4_NONE; return; } } bytes = uart_fifo_fill(h4_dev, tx.buf->data, tx.buf->len); net_buf_pull(tx.buf, bytes); if (tx.buf->len) { return; } done: tx.type = H4_NONE; net_buf_unref(tx.buf); tx.buf = net_buf_get(&tx.fifo, K_NO_WAIT); if (!tx.buf) { uart_irq_tx_disable(h4_dev); } }
static void notify_disconnected(struct bt_conn *conn) { struct bt_conn_cb *cb; bt_gatt_disconnected(conn); /* * FIXME: When disconnected NBLE stops advertising, this should * be fixed in the NBLE firmware, use this hack for now */ if (nble.keep_adv) { BT_WARN("Re-enable advertising on disconnect"); nble_gap_start_adv_req(); } for (cb = callback_list; cb; cb = cb->_next) { if (cb->disconnected) { cb->disconnected(conn, 0); } } }
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf) { struct bt_l2cap_hdr *hdr = (void *)buf->data; struct bt_l2cap_chan *chan; uint16_t cid; if (buf->len < sizeof(*hdr)) { BT_ERR("Too small L2CAP PDU received"); net_buf_unref(buf); return; } cid = sys_le16_to_cpu(hdr->cid); net_buf_pull(buf, sizeof(*hdr)); BT_DBG("Packet for CID %u len %u", cid, buf->len); switch (conn->type) { case BT_CONN_TYPE_LE: chan = bt_l2cap_le_lookup_rx_cid(conn, cid); break; #if defined(CONFIG_BLUETOOTH_BREDR) case BT_CONN_TYPE_BR: chan = bt_l2cap_br_lookup_rx_cid(conn, cid); break; #endif /* CONFIG_BLUETOOTH_BREDR */ default: chan = NULL; break; } if (!chan) { BT_WARN("Ignoring data for unknown CID 0x%04x", cid); net_buf_unref(buf); return; } l2cap_chan_recv(chan, buf); net_buf_unref(buf); }
static void notify_disconnected(struct bt_conn *conn) { struct bt_conn_cb *cb; bt_gatt_disconnected(conn); bt_smp_disconnected(conn); /* * FIXME: When disconnected NBLE stops advertising, this should * be fixed in the NBLE firmware, use this hack for now */ if (atomic_test_bit(&nble.flags, NBLE_FLAG_KEEP_ADVERTISING)) { BT_WARN("Re-enable advertising on disconnect"); nble_gap_start_adv_req(); } for (cb = callback_list; cb; cb = cb->_next) { if (cb->disconnected) { cb->disconnected(conn, 0); } } }
static inline void h4_get_type(void) { /* Get packet type */ if (uart_fifo_read(h4_dev, &rx.type, 1) != 1) { BT_WARN("Unable to read H:4 packet type"); rx.type = H4_NONE; return; } switch (rx.type) { case H4_EVT: rx.remaining = sizeof(rx.evt); rx.hdr_len = rx.remaining; break; case H4_ACL: rx.remaining = sizeof(rx.acl); rx.hdr_len = rx.remaining; break; default: BT_ERR("Unknown H:4 type 0x%02x", rx.type); rx.type = H4_NONE; } }
static int att_notify(struct bt_conn *conn, uint16_t handle, const void *data, size_t len) { struct net_buf *buf; struct bt_att_notify *nfy; buf = bt_att_create_pdu(conn, BT_ATT_OP_NOTIFY, sizeof(*nfy) + len); if (!buf) { BT_WARN("No buffer available to send notification"); return -ENOMEM; } BT_DBG("conn %p handle 0x%04x", conn, handle); nfy = net_buf_add(buf, sizeof(*nfy)); nfy->handle = sys_cpu_to_le16(handle); net_buf_add(buf, len); memcpy(nfy->value, data, len); bt_l2cap_send(conn, BT_L2CAP_CID_ATT, buf); return 0; }
int bt_gatt_attr_read_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { struct bt_gatt_chrc *chrc = attr->user_data; struct gatt_chrc pdu; const struct bt_gatt_attr *next; uint8_t value_len; pdu.properties = chrc->properties; /* BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part G] page 534: * 3.3.2 Characteristic Value Declaration * The Characteristic Value declaration contains the value of the * characteristic. It is the first Attribute after the characteristic * declaration. All characteristic definitions shall have a * Characteristic Value declaration. */ next = bt_gatt_attr_next(attr); if (!next) { BT_WARN("No value for characteristic at 0x%04x", attr->handle); pdu.value_handle = 0x0000; } else { pdu.value_handle = sys_cpu_to_le16(next->handle); } value_len = sizeof(pdu.properties) + sizeof(pdu.value_handle); if (chrc->uuid->type == BT_UUID_TYPE_16) { pdu.uuid16 = sys_cpu_to_le16(BT_UUID_16(chrc->uuid)->val); value_len += 2; } else { memcpy(pdu.uuid, BT_UUID_128(chrc->uuid)->val, 16); value_len += 16; } return bt_gatt_attr_read(conn, attr, buf, len, offset, &pdu, value_len); }
void bt_mesh_beacon_recv(struct net_buf_simple *buf) { u8_t type; BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->len < 1) { BT_ERR("Too short beacon"); return; } type = net_buf_simple_pull_u8(buf); switch (type) { case BEACON_TYPE_UNPROVISIONED: BT_DBG("Ignoring unprovisioned device beacon"); break; case BEACON_TYPE_SECURE: secure_beacon_recv(buf); break; default: BT_WARN("Unknown beacon type 0x%02x", type); break; } }
static void bt_uart_isr(struct device *unused) { static int remaining; uint8_t byte; int ret; static uint8_t hdr[4]; ARG_UNUSED(unused); while (uart_irq_update(h5_dev) && uart_irq_is_pending(h5_dev)) { if (!uart_irq_rx_ready(h5_dev)) { if (uart_irq_tx_ready(h5_dev)) { BT_DBG("transmit ready"); } else { BT_DBG("spurious interrupt"); } continue; } ret = uart_fifo_read(h5_dev, &byte, sizeof(byte)); if (!ret) { continue; } switch (h5.rx_state) { case START: if (byte == SLIP_DELIMITER) { h5.rx_state = HEADER; remaining = sizeof(hdr); } break; case HEADER: /* In a case we confuse ending slip delimeter * with starting one. */ if (byte == SLIP_DELIMITER) { remaining = sizeof(hdr); continue; } if (h5_unslip_byte(&byte) < 0) { h5_reset_rx(); continue; } memcpy(&hdr[sizeof(hdr) - remaining], &byte, 1); remaining--; if (remaining) { break; } remaining = H5_HDR_LEN(hdr); switch (H5_HDR_PKT_TYPE(hdr)) { case HCI_EVENT_PKT: h5.rx_buf = bt_buf_get_evt(); if (!h5.rx_buf) { BT_WARN("No available event buffers"); h5_reset_rx(); continue; } h5.rx_state = PAYLOAD; break; case HCI_ACLDATA_PKT: h5.rx_buf = bt_buf_get_acl(); if (!h5.rx_buf) { BT_WARN("No available data buffers"); h5_reset_rx(); continue; } h5.rx_state = PAYLOAD; break; case HCI_3WIRE_LINK_PKT: case HCI_3WIRE_ACK_PKT: h5.rx_buf = net_buf_get(&h5_sig, 0); if (!h5.rx_buf) { BT_WARN("No available signal buffers"); h5_reset_rx(); continue; } h5.rx_state = PAYLOAD; break; default: BT_ERR("Wrong packet type %u", H5_HDR_PKT_TYPE(hdr)); h5.rx_state = END; break; } break; case PAYLOAD: if (h5_unslip_byte(&byte) < 0) { h5_reset_rx(); continue; } memcpy(net_buf_add(h5.rx_buf, sizeof(byte)), &byte, sizeof(byte)); remaining--; if (!remaining) { h5.rx_state = END; } break; case END: if (byte != SLIP_DELIMITER) { BT_ERR("Missing ending SLIP_DELIMITER"); h5_reset_rx(); break; } BT_DBG("Received full packet: type %u", H5_HDR_PKT_TYPE(hdr)); /* Check when full packet is received, it can be done * when parsing packet header but we need to receive * full packet anyway to clear UART. */ if (H5_HDR_RELIABLE(hdr) && H5_HDR_SEQ(hdr) != h5.tx_ack) { BT_ERR("Seq expected %u got %u. Drop packet", h5.tx_ack, H5_HDR_SEQ(hdr)); h5_reset_rx(); break; } h5_process_complete_packet(hdr); h5.rx_state = START; break; } } }
static void bt_uart_isr(struct device *unused) { static struct net_buf *buf; static int remaining; ARG_UNUSED(unused); while (uart_irq_update(h4_dev) && uart_irq_is_pending(h4_dev)) { int read; if (!uart_irq_rx_ready(h4_dev)) { if (uart_irq_tx_ready(h4_dev)) { BT_DBG("transmit ready"); } else { BT_DBG("spurious interrupt"); } continue; } /* Beginning of a new packet */ if (!remaining) { uint8_t type; /* Get packet type */ read = h4_read(h4_dev, &type, sizeof(type), 0); if (read != sizeof(type)) { BT_WARN("Unable to read H4 packet type"); continue; } switch (type) { case H4_EVT: buf = h4_evt_recv(&remaining); break; case H4_ACL: buf = h4_acl_recv(&remaining); break; default: BT_ERR("Unknown H4 type %u", type); return; } BT_DBG("need to get %u bytes", remaining); if (buf && remaining > net_buf_tailroom(buf)) { BT_ERR("Not enough space in buffer"); net_buf_unref(buf); buf = NULL; } } if (!buf) { read = h4_discard(h4_dev, remaining); BT_WARN("Discarded %d bytes", read); remaining -= read; continue; } read = h4_read(h4_dev, net_buf_tail(buf), remaining, 0); buf->len += read; remaining -= read; BT_DBG("received %d bytes", read); if (!remaining) { BT_DBG("full packet received"); /* Pass buffer to the stack */ bt_recv(buf); buf = NULL; } } }
static inline void read_payload(void) { struct net_buf *buf; bool prio; int read; if (!rx.buf) { rx.buf = get_rx(K_NO_WAIT); if (!rx.buf) { if (rx.discardable) { BT_WARN("Discarding event 0x%02x", rx.evt.evt); rx.discard = rx.remaining; reset_rx(); return; } BT_WARN("Failed to allocate, deferring to rx_thread"); uart_irq_rx_disable(h4_dev); return; } BT_DBG("Allocated rx.buf %p", rx.buf); if (rx.remaining > net_buf_tailroom(rx.buf)) { BT_ERR("Not enough space in buffer"); rx.discard = rx.remaining; reset_rx(); return; } copy_hdr(rx.buf); } read = uart_fifo_read(h4_dev, net_buf_tail(rx.buf), rx.remaining); net_buf_add(rx.buf, read); rx.remaining -= read; BT_DBG("got %d bytes, remaining %u", read, rx.remaining); BT_DBG("Payload (len %u): %s", rx.buf->len, bt_hex(rx.buf->data, rx.buf->len)); if (rx.remaining) { return; } prio = (rx.type == H4_EVT && bt_hci_evt_is_prio(rx.evt.evt)); buf = rx.buf; rx.buf = NULL; if (rx.type == H4_EVT) { bt_buf_set_type(buf, BT_BUF_EVT); } else { bt_buf_set_type(buf, BT_BUF_ACL_IN); } reset_rx(); if (prio) { BT_DBG("Calling bt_recv_prio(%p)", buf); bt_recv_prio(buf); } else { BT_DBG("Putting buf %p to rx fifo", buf); net_buf_put(&rx.fifo, buf); } }
void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) { bt_conn_state_t old_state; BT_DBG("%s -> %s", state2str(conn->state), state2str(state)); if (conn->state == state) { BT_WARN("no transition"); return; } old_state = conn->state; conn->state = state; /* Actions needed for exiting the old state */ switch (old_state) { case BT_CONN_DISCONNECTED: /* Take a reference for the first state transition after * bt_conn_add_le() and keep it until reaching DISCONNECTED * again. */ bt_conn_ref(conn); break; case BT_CONN_CONNECT: if (conn->timeout) { fiber_delayed_start_cancel(conn->timeout); conn->timeout = NULL; /* Drop the reference taken by timeout fiber */ bt_conn_unref(conn); } break; default: break; } /* Actions needed for entering the new state */ switch (conn->state) { case BT_CONN_CONNECTED: nano_fifo_init(&conn->tx_queue); fiber_start(conn->stack, sizeof(conn->stack), conn_tx_fiber, (int)bt_conn_ref(conn), 0, 7, 0); bt_l2cap_connected(conn); notify_connected(conn); break; case BT_CONN_DISCONNECTED: /* Notify disconnection and queue a dummy buffer to wake * up and stop the tx fiber for states where it was * running. */ if (old_state == BT_CONN_CONNECTED || old_state == BT_CONN_DISCONNECT) { bt_l2cap_disconnected(conn); notify_disconnected(conn); nano_fifo_put(&conn->tx_queue, net_buf_get(&dummy, 0)); } else if (old_state == BT_CONN_CONNECT) { /* conn->err will be set in this case */ notify_connected(conn); } else if (old_state == BT_CONN_CONNECT_SCAN && conn->err) { /* this indicate LE Create Connection failed */ notify_connected(conn); } /* Release the reference we took for the very first * state transition. */ bt_conn_unref(conn); break; case BT_CONN_CONNECT_SCAN: break; case BT_CONN_CONNECT: /* * Timer is needed only for LE. For other link types controller * will handle connection timeout. */ if (conn->type != BT_CONN_TYPE_LE) { break; } /* Add LE Create Connection timeout */ conn->timeout = fiber_delayed_start(conn->stack, sizeof(conn->stack), timeout_fiber, (int)bt_conn_ref(conn), 0, 7, 0, CONN_TIMEOUT); break; case BT_CONN_DISCONNECT: break; default: BT_WARN("no valid (%u) state was set", state); break; } }
static void secure_beacon_recv(struct net_buf_simple *buf) { u8_t *data, *net_id, *auth; struct bt_mesh_subnet *sub; u32_t iv_index; bool new_key, kr_change, iv_change; u8_t flags; if (buf->len < 21) { BT_ERR("Too short secure beacon (len %u)", buf->len); return; } sub = cache_check(buf->data); if (sub) { /* We've seen this beacon before - just update the stats */ goto update_stats; } /* So we can add to the cache if auth matches */ data = buf->data; flags = net_buf_simple_pull_u8(buf); net_id = buf->data; net_buf_simple_pull(buf, 8); iv_index = net_buf_simple_pull_be32(buf); auth = buf->data; BT_DBG("flags 0x%02x id %s iv_index 0x%08x", flags, bt_hex(net_id, 8), iv_index); sub = bt_mesh_subnet_find(net_id, flags, iv_index, auth, &new_key); if (!sub) { BT_DBG("No subnet that matched beacon"); return; } if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !new_key) { BT_WARN("Ignoring Phase 2 KR Update secured using old key"); return; } cache_add(data, sub); /* If we have NetKey0 accept initiation only from it */ if (bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY) && sub->net_idx != BT_MESH_KEY_PRIMARY) { BT_WARN("Ignoring secure beacon on non-primary subnet"); goto update_stats; } BT_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x", sub->net_idx, iv_index, bt_mesh.iv_index); if (bt_mesh.ivu_initiator && bt_mesh.iv_update == BT_MESH_IV_UPDATE(flags)) { bt_mesh_beacon_ivu_initiator(false); } iv_change = bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(flags)); kr_change = bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(flags), new_key); if (kr_change) { bt_mesh_net_beacon_update(sub); } if (iv_change) { /* Update all subnets */ bt_mesh_net_sec_update(NULL); } else if (kr_change) { /* Key Refresh without IV Update only impacts one subnet */ bt_mesh_net_sec_update(sub); } update_stats: if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED && sub->beacons_cur < 0xff) { sub->beacons_cur++; } }
static void l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) { struct bt_l2cap *l2cap = CONTAINER_OF(chan, struct bt_l2cap, chan); struct bt_l2cap_sig_hdr *hdr = (void *)buf->data; uint16_t len; if (buf->len < sizeof(*hdr)) { BT_ERR("Too small L2CAP signaling PDU"); return; } len = sys_le16_to_cpu(hdr->len); net_buf_pull(buf, sizeof(*hdr)); BT_DBG("Signaling code 0x%02x ident %u len %u", hdr->code, hdr->ident, len); if (buf->len != len) { BT_ERR("L2CAP length mismatch (%u != %u)", buf->len, len); return; } if (!hdr->ident) { BT_ERR("Invalid ident value in L2CAP PDU"); return; } switch (hdr->code) { case BT_L2CAP_CONN_PARAM_RSP: le_conn_param_rsp(l2cap, buf); break; #if defined(CONFIG_BLUETOOTH_CENTRAL) case BT_L2CAP_CONN_PARAM_REQ: le_conn_param_update_req(l2cap, hdr->ident, buf); break; #endif /* CONFIG_BLUETOOTH_CENTRAL */ #if defined(CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL) case BT_L2CAP_LE_CONN_REQ: le_conn_req(l2cap, hdr->ident, buf); break; case BT_L2CAP_LE_CONN_RSP: le_conn_rsp(l2cap, hdr->ident, buf); break; case BT_L2CAP_DISCONN_REQ: le_disconn_req(l2cap, hdr->ident, buf); break; case BT_L2CAP_DISCONN_RSP: le_disconn_rsp(l2cap, hdr->ident, buf); break; case BT_L2CAP_LE_CREDITS: le_credits(l2cap, hdr->ident, buf); break; case BT_L2CAP_CMD_REJECT: reject_cmd(l2cap, hdr->ident, buf); break; #else case BT_L2CAP_CMD_REJECT: /* Ignored */ break; #endif /* CONFIG_BLUETOOTH_L2CAP_DYNAMIC_CHANNEL */ default: BT_WARN("Unknown L2CAP PDU code 0x%02x", hdr->code); l2cap_send_reject(chan->conn, hdr->ident, BT_L2CAP_REJ_NOT_UNDERSTOOD, NULL, 0); break; } }
void bt_uart_isr(void *unused) { static struct bt_buf *buf; static int remaining; ARG_UNUSED(unused); while (uart_irq_update(UART) && uart_irq_is_pending(UART)) { int read; if (!uart_irq_rx_ready(UART)) { if (uart_irq_tx_ready(UART)) { BT_DBG("transmit ready\n"); } else { BT_DBG("spurious interrupt\n"); } continue; } /* Beginning of a new packet */ if (!remaining) { uint8_t type; /* Get packet type */ read = bt_uart_read(UART, &type, sizeof(type), 0); if (read != sizeof(type)) { BT_WARN("Unable to read H4 packet type\n"); continue; } switch (type) { case H4_EVT: buf = bt_uart_evt_recv(&remaining); break; case H4_ACL: buf = bt_uart_acl_recv(&remaining); break; default: BT_ERR("Unknown H4 type %u\n", type); return; } if (buf && remaining > bt_buf_tailroom(buf)) { BT_ERR("Not enough space in buffer\n"); goto failed; } BT_DBG("need to get %u bytes\n", remaining); } if (!buf) { read = bt_uart_discard(UART, remaining); BT_WARN("Discarded %d bytes\n", read); remaining -= read; continue; } read = bt_uart_read(UART, bt_buf_tail(buf), remaining, 0); buf->len += read; remaining -= read; BT_DBG("received %d bytes\n", read); if (!remaining) { BT_DBG("full packet received\n"); /* Pass buffer to the stack */ bt_recv(buf); buf = NULL; } } return; failed: bt_buf_put(buf); remaining = 0; buf = NULL; }
void on_nble_gap_sm_common_rsp(const struct nble_gap_sm_response *rsp) { if (rsp->status) { BT_WARN("gap sm request failed: %d", rsp->status); } }