Unknown options respose for Configure Respose packet has a different layout that that of unaccepted options, so it needs special code to handle it. Before: > ACL Data RX: Handle 12 flags 0x02 dlen 15 L2CAP: Configure Response (0x05) ident 2 len 7 Source CID: 64 Flags: 0x0000 Result: Failure - unknown options (0x0003) 04 After: > ACL Data RX: Handle 12 flags 0x02 dlen 15 L2CAP: Configure Response (0x05) ident 3 len 7 Source CID: 65 Flags: 0x0000 Result: Failure - unknown options (0x0003) Option: Retransmission and Flow Control (0x04) --- Changes since [v1]: - Code converted to use l2cap_frame_get_u8() and l2cap_frame_pull() [v1] https://lore.kernel.org/linux-bluetooth/20190522013216.22493-1-andrew.smirnov@xxxxxxxxx/ monitor/l2cap.c | 54 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/monitor/l2cap.c b/monitor/l2cap.c index 26719ac5e..41967a731 100644 --- a/monitor/l2cap.c +++ b/monitor/l2cap.c @@ -705,6 +705,41 @@ static struct { { } }; +static void lookup_option_by_type(uint8_t type, const char **str, + uint8_t *expect_len) +{ + int i; + + for (i = 0; options_table[i].str; i++) { + if (options_table[i].type == type) { + *str = options_table[i].str; + if (expect_len) + *expect_len = options_table[i].len; + return; + } + } + + *str = "Unknown"; + if (expect_len) + *expect_len = 0; +} + +static void print_unknown_options(const struct l2cap_frame *source, + uint8_t offset) +{ + struct l2cap_frame frame; + uint8_t type; + + l2cap_frame_pull(&frame, source, offset); + + while (l2cap_frame_get_u8(&frame, &type)) { + const char *str; + + lookup_option_by_type(type, &str, NULL); + print_field("Option: %s (0x%2.2x)", str, type); + } +} + static void print_config_options(const struct l2cap_frame *frame, uint8_t offset, uint16_t cid, bool response) { @@ -713,20 +748,13 @@ static void print_config_options(const struct l2cap_frame *frame, uint16_t consumed = 0; while (consumed < size - 2) { - const char *str = "Unknown"; + const char *str; uint8_t type = data[consumed] & 0x7f; uint8_t hint = data[consumed] & 0x80; uint8_t len = data[consumed + 1]; - uint8_t expect_len = 0; - int i; + uint8_t expect_len; - for (i = 0; options_table[i].str; i++) { - if (options_table[i].type == type) { - str = options_table[i].str; - expect_len = options_table[i].len; - break; - } - } + lookup_option_by_type(type, &str, &expect_len); print_field("Option: %s (0x%2.2x) [%s]", str, type, hint ? "hint" : "mandatory"); @@ -1122,7 +1150,11 @@ static void sig_config_rsp(const struct l2cap_frame *frame) print_cid("Source", pdu->scid); print_config_flags(pdu->flags); print_config_result(pdu->result); - print_config_options(frame, 6, le16_to_cpu(pdu->scid), true); + if (pdu->result == 0x0003) + print_unknown_options(frame, 6); + else + print_config_options(frame, 6, le16_to_cpu(pdu->scid), true); + } static void sig_disconn_req(const struct l2cap_frame *frame) -- 2.21.0