diff --git a/monitor/bt.h b/monitor/bt.h
index 0f97f97..f91545d 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
uint8_t status;
} __attribute__ ((packed));
+struct bt_l2cap_hdr_att {
+ uint8_t code;
+} __attribute__ ((packed));
+
+struct bt_l2cap_hdr_smp {
+ uint8_t code;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_PAIRING_REQUEST 0x01
+struct bt_l2cap_smp_pairing_request {
+ uint8_t io_capa;
+ uint8_t oob_data;
+ uint8_t auth_req;
+ uint8_t max_key_size;
+ uint8_t init_key_dist;
+ uint8_t resp_key_dist;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_PAIRING_RESPONSE 0x02
+struct bt_l2cap_smp_pairing_response {
+ uint8_t io_capa;
+ uint8_t oob_data;
+ uint8_t auth_req;
+ uint8_t max_key_size;
+ uint8_t init_key_dist;
+ uint8_t resp_key_dist;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_PAIRING_CONFIRM 0x03
+struct bt_l2cap_smp_pairing_confirm {
+ uint8_t value[16];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_PAIRING_RANDOM 0x04
+struct bt_l2cap_smp_pairing_random {
+ uint8_t value[16];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_PAIRING_FAILED 0x05
+struct bt_l2cap_smp_pairing_failed {
+ uint8_t reason;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_ENCRYPT_INFO 0x06
+struct bt_l2cap_smp_encrypt_info {
+ uint8_t ltk[16];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_MASTER_IDENT 0x07
+struct bt_l2cap_smp_master_ident {
+ uint16_t ediv;
+ uint64_t rand;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_IDENT_INFO 0x08
+struct bt_l2cap_smp_ident_info {
+ uint8_t irk[16];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_IDENT_ADDR_INFO 0x09
+struct bt_l2cap_smp_ident_addr_info {
+ uint8_t addr_type;
+ uint8_t addr[6];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_SIGNING_INFO 0x0a
+struct bt_l2cap_smp_signing_info {
+ uint8_t csrk[16];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_SECURITY_REQUEST 0x0b
+struct bt_l2cap_smp_security_request {
+ uint8_t auth_req;
+} __attribute__ ((packed));
+
struct bt_sdp_hdr {
uint8_t pdu;
uint16_t tid;
diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index 48c3d1c..6904d05 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
opcode_data->func(&frame);
}
+static void print_hex_field(const char *label, const uint8_t *data,
+ uint8_t len)
+{
+ char str[len * 2 + 1];
+ uint8_t i;
+
+ for (i = 0; i < len; i++)
+ sprintf(str + (i * 2), "%2.2x", data[i]);
+
+ print_field("%s: %s", label, str);
+}
+
+static void print_addr(const uint8_t *addr, uint8_t addr_type)
+{
+ const char *str;
+
+ switch (addr_type) {
+ case 0x00:
+ print_field("Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ addr[5], addr[4], addr[3],
+ addr[2], addr[1], addr[0]);
+ break;
+ case 0x01:
+ switch ((addr[5] & 0xc0) >> 6) {
+ case 0x00:
+ str = "Non-Resolvable";
+ break;
+ case 0x01:
+ str = "Resolvable";
+ break;
+ case 0x03:
+ str = "Static";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X"
+ " (%s)", addr[5], addr[4], addr[3],
+ addr[2], addr[1], addr[0], str);
+ break;
+ default:
+ print_field("Address: %2.2X-%2.2X-%2.2X-%2.2X-%2.2X-%2.2X",
+ addr[5], addr[4], addr[3],
+ addr[2], addr[1], addr[0]);
+ break;
+ }
+}
+
+static void print_addr_type(uint8_t addr_type)
+{
+ const char *str;
+
+ switch (addr_type) {
+ case 0x00:
+ str = "Public";
+ break;
+ case 0x01:
+ str = "Random";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Address type: %s (0x%2.2x)", str, addr_type);
+}
+
+static void print_smp_io_capa(uint8_t io_capa)
+{
+ const char *str;
+
+ switch (io_capa) {
+ case 0x00:
+ str = "DisplayOnly";
+ break;
+ case 0x01:
+ str = "DisplayYesNo";
+ break;
+ case 0x02:
+ str = "KeyboardOnly";
+ break;
+ case 0x03:
+ str = "NoInputNoOutput";
+ break;
+ case 0x04:
+ str = "KeyboardDisplay";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("IO capability: %s (0x%2.2x)", str, io_capa);
+}
+
+static void print_smp_oob_data(uint8_t oob_data)
+{
+ const char *str;
+
+ switch (oob_data) {
+ case 0x00:
+ str = "Authentication data not present";
+ break;
+ case 0x01:
+ str = "Authentication data from remote device present";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("OOB data: %s (0x%2.2x)", str, oob_data);
+}
+
+static void print_smp_auth_req(uint8_t auth_req)
+{
+ const char *str;
+
+ switch (auth_req & 0x03) {
+ case 0x00:
+ str = "No bonding";
+ break;
+ case 0x01:
+ str = "Bonding";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Authentication requirement: %s - %s (0x%2.2x)",
+ str, (auth_req & 0x04) ? "MITM" : "No MITM", auth_req);
+}
+
+static void smp_pairing_request(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_pairing_request *pdu = frame->data;
+
+ print_smp_io_capa(pdu->io_capa);
+ print_smp_oob_data(pdu->oob_data);
+ print_smp_auth_req(pdu->auth_req);
+
+ print_field("Max encryption key size: %d", pdu->max_key_size);
+ print_field("Initiator key distribution: 0x%2.2x", pdu->init_key_dist);
+ print_field("Responder key distribution: 0x%2.2x", pdu->resp_key_dist);
+}
+
+static void smp_pairing_response(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_pairing_response *pdu = frame->data;
+
+ print_smp_io_capa(pdu->io_capa);
+ print_smp_oob_data(pdu->oob_data);
+ print_smp_auth_req(pdu->auth_req);
+
+ print_field("Max encryption key size: %d", pdu->max_key_size);
+ print_field("Initiator key distribution: 0x%2.2x", pdu->init_key_dist);
+ print_field("Responder key distribution: 0x%2.2x", pdu->resp_key_dist);
+}
+
+static void smp_pairing_confirm(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_pairing_confirm *pdu = frame->data;
+
+ print_hex_field("Confim value", pdu->value, 16);
+}
+
+static void smp_pairing_random(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_pairing_random *pdu = frame->data;
+
+ print_hex_field("Random value", pdu->value, 16);
+}
+
+static void smp_pairing_failed(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_pairing_failed *pdu = frame->data;
+ const char *str;
+
+ switch (pdu->reason) {
+ case 0x01:
+ str = "Passkey entry failed";
+ break;
+ case 0x02:
+ str = "OOB not available";
+ break;
+ case 0x03:
+ str = "Authentication requirements";
+ break;
+ case 0x04:
+ str = "Confirm value failed";
+ break;
+ case 0x05:
+ str = "Pairing not supported";
+ break;
+ case 0x06:
+ str = "Encryption key size";
+ break;
+ case 0x07:
+ str = "Command not supported";
+ break;
+ case 0x08:
+ str = "Unspecified reason";
+ break;
+ case 0x09:
+ str = "Repeated attempts";
+ break;
+ case 0x0a:
+ str = "Invalid parameters";
+ break;
+ default:
+ str = "Reserved";
+ break;
+ }
+
+ print_field("Reason: %s (0x%2.2x)", str, pdu->reason);
+}
+
+static void smp_encrypt_info(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_encrypt_info *pdu = frame->data;
+
+ print_hex_field("Long term key", pdu->ltk, 16);
+}
+
+static void smp_master_ident(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_master_ident *pdu = frame->data;
+
+ print_field("EDIV: 0x%4.4x", btohs(pdu->ediv));
+ print_field("Rand: 0x%16.16" PRIx64, btohll(pdu->rand));
+}
+
+static void smp_ident_info(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_ident_info *pdu = frame->data;
+
+ print_hex_field("Identity resolving key", pdu->irk, 16);
+}
+
+static void smp_ident_addr_info(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_ident_addr_info *pdu = frame->data;
+
+ print_addr_type(pdu->addr_type);
+ print_addr(pdu->addr, pdu->addr_type);
+}
+
+static void smp_signing_info(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_signing_info *pdu = frame->data;
+
+ print_hex_field("Signature key", pdu->csrk, 16);
+}
+
+static void smp_security_request(const struct l2cap_frame *frame)
+{
+ const struct bt_l2cap_smp_security_request *pdu = frame->data;
+
+ print_smp_auth_req(pdu->auth_req);
+}
+
struct smp_opcode_data {
uint8_t opcode;
const char *str;
};
static const struct smp_opcode_data smp_opcode_table[] = {
- { 0x01, "Pairing Request" },
- { 0x02, "Pairing Response" },
- { 0x03, "Pairing Confirm" },
- { 0x04, "Pairing Random" },
- { 0x05, "Pairing Failed" },
- { 0x06, "Encryption Information" },
- { 0x07, "Master Identification" },
- { 0x08, "Identity Information" },
- { 0x09, "Identity Address Information" },
- { 0x0a, "Signing Information" },
- { 0x0b, "Security Request" },
+ { 0x01, "Pairing Request",
+ smp_pairing_request, 6, true },
+ { 0x02, "Pairing Response",
+ smp_pairing_response, 6, true },
+ { 0x03, "Pairing Confirm",
+ smp_pairing_confirm, 16, true },
+ { 0x04, "Pairing Random",
+ smp_pairing_random, 16, true },
+ { 0x05, "Pairing Failed",
+ smp_pairing_failed, 1, true },
+ { 0x06, "Encryption Information",
+ smp_encrypt_info, 16, true },
+ { 0x07, "Master Identification",
+ smp_master_ident, 10, true },
+ { 0x08, "Identity Information",
+ smp_ident_info, 16, true },
+ { 0x09, "Identity Address Information",
+ smp_ident_addr_info, 7, true },
+ { 0x0a, "Signing Information",
+ smp_signing_info, 16, true },
+ { 0x0b, "Security Request",
+ smp_security_request, 1, true },
{ }
};