void control_message(uint16_t opcode, const void *data, uint16_t size) { if (!decode_control) return; switch (opcode) { case MGMT_EV_INDEX_ADDED: mgmt_index_added(size, data); break; case MGMT_EV_INDEX_REMOVED: mgmt_index_removed(size, data); break; case MGMT_EV_CONTROLLER_ERROR: mgmt_controller_error(size, data); break; case MGMT_EV_NEW_SETTINGS: mgmt_new_settings(size, data); break; case MGMT_EV_CLASS_OF_DEV_CHANGED: mgmt_class_of_dev_changed(size, data); break; case MGMT_EV_LOCAL_NAME_CHANGED: mgmt_local_name_changed(size, data); break; case MGMT_EV_NEW_LINK_KEY: mgmt_new_link_key(size, data); break; case MGMT_EV_NEW_LONG_TERM_KEY: mgmt_new_long_term_key(size, data); break; case MGMT_EV_DEVICE_CONNECTED: mgmt_device_connected(size, data); break; case MGMT_EV_DEVICE_DISCONNECTED: mgmt_device_disconnected(size, data); break; case MGMT_EV_CONNECT_FAILED: mgmt_connect_failed(size, data); break; case MGMT_EV_PIN_CODE_REQUEST: mgmt_pin_code_request(size, data); break; case MGMT_EV_USER_CONFIRM_REQUEST: mgmt_user_confirm_request(size, data); break; case MGMT_EV_USER_PASSKEY_REQUEST: mgmt_user_passkey_request(size, data); break; case MGMT_EV_AUTH_FAILED: mgmt_auth_failed(size, data); break; case MGMT_EV_DEVICE_FOUND: mgmt_device_found(size, data); break; case MGMT_EV_DISCOVERING: mgmt_discovering(size, data); break; case MGMT_EV_DEVICE_BLOCKED: mgmt_device_blocked(size, data); break; case MGMT_EV_DEVICE_UNBLOCKED: mgmt_device_unblocked(size, data); break; case MGMT_EV_DEVICE_UNPAIRED: mgmt_device_unpaired(size, data); break; case MGMT_EV_PASSKEY_NOTIFY: mgmt_passkey_notify(size, data); break; case MGMT_EV_NEW_IRK: mgmt_new_irk(size, data); break; case MGMT_EV_NEW_CSRK: mgmt_new_csrk(size, data); break; case MGMT_EV_DEVICE_ADDED: mgmt_device_added(size, data); break; case MGMT_EV_DEVICE_REMOVED: mgmt_device_removed(size, data); break; case MGMT_EV_NEW_CONN_PARAM: mgmt_new_conn_param(size, data); break; case MGMT_EV_UNCONF_INDEX_ADDED: mgmt_unconf_index_added(size, data); break; case MGMT_EV_UNCONF_INDEX_REMOVED: mgmt_unconf_index_removed(size, data); break; case MGMT_EV_NEW_CONFIG_OPTIONS: mgmt_new_config_options(size, data); break; case MGMT_EV_EXT_INDEX_ADDED: mgmt_ext_index_added(size, data); break; case MGMT_EV_EXT_INDEX_REMOVED: mgmt_ext_index_removed(size, data); break; case MGMT_EV_ADVERTISING_ADDED: mgmt_advertising_added(size, data); break; case MGMT_EV_ADVERTISING_REMOVED: mgmt_advertising_removed(size, data); break; default: printf("* Unknown control (code %d len %d)\n", opcode, size); packet_hexdump(data, size); break; } }
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, u8 local_io, u8 remote_io) { struct hci_conn *hcon = conn->hcon; struct smp_chan *smp = conn->smp_chan; u8 method; u32 passkey = 0; int ret = 0; /* Initialize key for JUST WORKS */ memset(smp->tk, 0, sizeof(smp->tk)); clear_bit(SMP_FLAG_TK_VALID, &smp->smp_flags); BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io); /* If neither side wants MITM, use JUST WORKS */ /* If either side has unknown io_caps, use JUST WORKS */ /* Otherwise, look up method from the table */ if (!(auth & SMP_AUTH_MITM) || local_io > SMP_IO_KEYBOARD_DISPLAY || remote_io > SMP_IO_KEYBOARD_DISPLAY) method = JUST_WORKS; else method = gen_method[remote_io][local_io]; /* If not bonding, don't ask user to confirm a Zero TK */ if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM) method = JUST_WORKS; /* If Just Works, Continue with Zero TK */ if (method == JUST_WORKS) { set_bit(SMP_FLAG_TK_VALID, &smp->smp_flags); return 0; } /* Not Just Works/Confirm results in MITM Authentication */ if (method != JUST_CFM) set_bit(SMP_FLAG_MITM_AUTH, &smp->smp_flags); /* If both devices have Keyoard-Display I/O, the master * Confirms and the slave Enters the passkey. */ if (method == OVERLAP) { if (hcon->link_mode & HCI_LM_MASTER) method = CFM_PASSKEY; else method = REQ_PASSKEY; } /* Generate random passkey. Not valid until confirmed. */ if (method == CFM_PASSKEY) { u8 key[16]; memset(key, 0, sizeof(key)); get_random_bytes(&passkey, sizeof(passkey)); passkey %= 1000000; put_unaligned_le32(passkey, key); swap128(key, smp->tk); BT_DBG("PassKey: %d", passkey); } hci_dev_lock(hcon->hdev); if (method == REQ_PASSKEY) ret = mgmt_user_passkey_request(hcon->hdev, conn->dst, hcon->type, hcon->dst_type); else ret = mgmt_user_confirm_request(hcon->hdev, conn->dst, hcon->type, hcon->dst_type, cpu_to_le32(passkey), 0); hci_dev_unlock(hcon->hdev); return ret; }
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, u8 local_io, u8 remote_io) { struct hci_conn *hcon = conn->hcon; u8 method; u32 passkey = 0; int ret = 0; /* Initialize key to JUST WORKS */ memset(hcon->tk, 0, sizeof(hcon->tk)); hcon->tk_valid = FALSE; hcon->auth = auth; /* By definition, OOB data will be used if both sides have it available */ if (remote_oob && hcon->oob) { method = SMP_REQ_OOB; goto agent_request; } BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io); /* If neither side wants MITM, use JUST WORKS */ /* If either side has unknown io_caps, use JUST_WORKS */ if (!(auth & SMP_AUTH_MITM) || local_io > SMP_IO_KEYBOARD_DISPLAY || remote_io > SMP_IO_KEYBOARD_DISPLAY) { hcon->auth &= ~SMP_AUTH_MITM; hcon->tk_valid = TRUE; return 0; } /* MITM is now officially requested, but not required */ /* Determine what we need (if anything) from the agent */ method = gen_method[local_io][remote_io]; BT_DBG("tk_method: %d", method); if (method == SMP_JUST_WORKS || method == SMP_JUST_CFM) hcon->auth &= ~SMP_AUTH_MITM; /* Don't bother confirming unbonded JUST_WORKS */ if (!(auth & SMP_AUTH_BONDING) && method == SMP_JUST_CFM) { hcon->tk_valid = TRUE; return 0; } else if (method == SMP_JUST_WORKS) { hcon->tk_valid = TRUE; return 0; } else if (method == SMP_OVERLAP) { if (hcon->link_mode & HCI_LM_MASTER) method = SMP_CFM_PASSKEY; else method = SMP_REQ_PASSKEY; } BT_DBG("tk_method-2: %d", method); if (method == SMP_CFM_PASSKEY) { u8 key[16]; /* Generate a passkey for display. It is not valid until * confirmed. */ memset(key, 0, sizeof(key)); get_random_bytes(&passkey, sizeof(passkey)); passkey %= 1000000; put_unaligned_le32(passkey, key); swap128(key, hcon->tk); BT_DBG("PassKey: %d", passkey); } agent_request: hci_dev_lock(hcon->hdev); switch (method) { case SMP_REQ_PASSKEY: ret = mgmt_user_confirm_request(hcon->hdev->id, HCI_EV_USER_PASSKEY_REQUEST, conn->dst, 0); break; case SMP_CFM_PASSKEY: default: ret = mgmt_user_confirm_request(hcon->hdev->id, HCI_EV_USER_CONFIRM_REQUEST, conn->dst, passkey); break; } hci_dev_unlock(hcon->hdev); return ret; }
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, u8 local_io, u8 remote_io) { struct hci_conn *hcon = conn->hcon; u8 method; u32 passkey = 0; int ret = 0; memset(hcon->tk, 0, sizeof(hcon->tk)); hcon->tk_valid = FALSE; hcon->auth = auth; if (remote_oob && hcon->oob) { method = SMP_REQ_OOB; goto agent_request; } BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io); if (!(auth & SMP_AUTH_MITM) || local_io > SMP_IO_KEYBOARD_DISPLAY || remote_io > SMP_IO_KEYBOARD_DISPLAY) { hcon->auth &= ~SMP_AUTH_MITM; hcon->tk_valid = TRUE; return 0; } method = gen_method[local_io][remote_io]; BT_DBG("tk_method: %d", method); if (method == SMP_JUST_WORKS || method == SMP_JUST_CFM) hcon->auth &= ~SMP_AUTH_MITM; if (!(auth & SMP_AUTH_BONDING) && method == SMP_JUST_CFM) { hcon->tk_valid = TRUE; return 0; } else if (method == SMP_JUST_WORKS) { hcon->tk_valid = TRUE; return 0; } else if (method == SMP_OVERLAP) { if (hcon->link_mode & HCI_LM_MASTER) method = SMP_CFM_PASSKEY; else method = SMP_REQ_PASSKEY; } BT_DBG("tk_method-2: %d", method); if (method == SMP_CFM_PASSKEY) { u8 key[16]; memset(key, 0, sizeof(key)); get_random_bytes(&passkey, sizeof(passkey)); passkey %= 1000000; put_unaligned_le32(passkey, key); swap128(key, hcon->tk); BT_DBG("PassKey: %d", passkey); } agent_request: hci_dev_lock(hcon->hdev); switch (method) { case SMP_REQ_PASSKEY: ret = mgmt_user_confirm_request(hcon->hdev->id, HCI_EV_USER_PASSKEY_REQUEST, conn->dst, 0); break; case SMP_CFM_PASSKEY: default: ret = mgmt_user_confirm_request(hcon->hdev->id, HCI_EV_USER_CONFIRM_REQUEST, conn->dst, passkey); break; } hci_dev_unlock(hcon->hdev); return ret; }
static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data) { char buf[MGMT_BUF_SIZE]; struct mgmt_hdr *hdr = (void *) buf; int sk; ssize_t ret; uint16_t len, opcode, index; DBG("cond %d", cond); if (cond & G_IO_NVAL) return FALSE; sk = g_io_channel_unix_get_fd(io); if (cond & (G_IO_ERR | G_IO_HUP)) { error("Error on management socket"); return FALSE; } ret = read(sk, buf, sizeof(buf)); if (ret < 0) { error("Unable to read from management socket: %s (%d)", strerror(errno), errno); return TRUE; } DBG("Received %zd bytes from management socket", ret); if (ret < MGMT_HDR_SIZE) { error("Too small Management packet"); return TRUE; } opcode = btohs(bt_get_unaligned(&hdr->opcode)); len = btohs(bt_get_unaligned(&hdr->len)); index = btohs(bt_get_unaligned(&hdr->index)); if (ret != MGMT_HDR_SIZE + len) { error("Packet length mismatch. ret %zd len %u", ret, len); return TRUE; } switch (opcode) { case MGMT_EV_CMD_COMPLETE: mgmt_cmd_complete(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_CMD_STATUS: mgmt_cmd_status(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_CONTROLLER_ERROR: mgmt_controller_error(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_INDEX_ADDED: mgmt_index_added(sk, index); break; case MGMT_EV_INDEX_REMOVED: mgmt_index_removed(sk, index); break; case MGMT_EV_POWERED: mgmt_powered(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_DISCOVERABLE: mgmt_discoverable(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_CONNECTABLE: mgmt_connectable(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_PAIRABLE: mgmt_pairable(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_NEW_KEY: mgmt_new_key(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_DEVICE_CONNECTED: mgmt_device_connected(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_DEVICE_DISCONNECTED: mgmt_device_disconnected(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_CONNECT_FAILED: mgmt_connect_failed(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_PIN_CODE_REQUEST: mgmt_pin_code_request(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_USER_CONFIRM_REQUEST: mgmt_user_confirm_request(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_AUTH_FAILED: mgmt_auth_failed(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_LOCAL_NAME_CHANGED: mgmt_local_name_changed(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_DEVICE_FOUND: mgmt_device_found(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_REMOTE_NAME: mgmt_remote_name(sk, index, buf + MGMT_HDR_SIZE, len); break; case MGMT_EV_DISCOVERING: mgmt_discovering(sk, index, buf + MGMT_HDR_SIZE, len); break; default: error("Unknown Management opcode %u (index %u)", opcode, index); break; } return TRUE; }