static int ah(const u8_t irk[16], const u8_t r[3], u8_t out[3]) { u8_t res[16]; int err; BT_DBG("irk %s, r %s", bt_hex(irk, 16), bt_hex(r, 3)); /* r' = padding || r */ memcpy(res, r, 3); memset(res + 3, 0, 13); err = bt_encrypt_le(irk, res, res); if (err) { return err; } /* The output of the random address function ah is: * ah(h, r) = e(k, r') mod 2^24 * The output of the security function e is then truncated to 24 bits * by taking the least significant 24 bits of the output of e as the * result of ah. */ memcpy(out, res, 3); return 0; }
void bt_mesh_beacon_create(struct bt_mesh_subnet *sub, struct net_buf_simple *buf) { u8_t flags = bt_mesh_net_flags(sub); struct bt_mesh_subnet_keys *keys; net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE); if (sub->kr_flag) { keys = &sub->keys[1]; } else { keys = &sub->keys[0]; } net_buf_simple_add_u8(buf, flags); /* Network ID */ net_buf_simple_add_mem(buf, keys->net_id, 8); /* IV Index */ net_buf_simple_add_be32(buf, bt_mesh.iv_index); net_buf_simple_add_mem(buf, sub->auth, 8); BT_DBG("net_idx 0x%04x flags 0x%02x NetID %s", sub->net_idx, flags, bt_hex(keys->net_id, 8)); BT_DBG("IV Index 0x%08x Auth %s", bt_mesh.iv_index, bt_hex(sub->auth, 8)); }
bool bt_rpa_irk_matches(const u8_t irk[16], const bt_addr_t *addr) { u8_t hash[3]; int err; BT_DBG("IRK %s bdaddr %s", bt_hex(irk, 16), bt_addr_str(addr)); err = ah(irk, addr->val + 3, hash); if (err) { return false; } return !memcmp(addr->val, hash, 3); }
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 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); } }
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++; } }