Hi Andrey, On Wed, May 22, 2019 at 4:34 AM Andrey Smirnov <andrew.smirnov@xxxxxxxxx> wrote: > > Unknown options respose for Configure Respose packet has a different > layout than 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) > --- > monitor/l2cap.c | 56 ++++++++++++++++++++++++++++++++++++++----------- > 1 file changed, 44 insertions(+), 12 deletions(-) > > diff --git a/monitor/l2cap.c b/monitor/l2cap.c > index 26719ac5e..6983f80f0 100644 > --- a/monitor/l2cap.c > +++ b/monitor/l2cap.c > @@ -705,6 +705,42 @@ 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 *frame, > + uint8_t offset) > +{ > + const uint8_t *data = frame->data + offset; > + uint16_t size = frame->size - offset; > + uint16_t consumed = 0; > + > + while (size--) { Id expected this to use l2cap_frame_get_u8 for fetching the type so you don't have to create a custom code to iterate into the frame, the offset can be handled with l2cap_frame_pull. > + const char *str; > + uint8_t type = data[consumed++] & 0x7f; > + > + 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,24 +749,16 @@ 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"); > - > if (expect_len == 0) { > consumed += 2; > break; > @@ -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 > -- Luiz Augusto von Dentz