This fixes the following crash caused by notify callback being NULL:
Jump to the invalid address stated on the next line
at 0x0: ???
by 0x1E8375: print_notify (att.c:5420)
by 0x1E9464: att_multiple_vl_rsp (att.c:5463)
by 0x20D39E: att_packet (att.c:5637)
by 0x1B2054: l2cap_frame (l2cap.c:2567)
by 0x1B4A4D: l2cap_packet (l2cap.c:2708)
by 0x19AD43: packet_hci_acldata (packet.c:12522)
by 0x19CF07: packet_monitor (packet.c:4249)
by 0x152405: data_callback (control.c:973)
by 0x2204F6: mainloop_run (mainloop.c:106)
by 0x221017: mainloop_run_with_signal (mainloop-notify.c:189)
by 0x14F387: main (main.c:298)
Address 0x0 is not stack'd, malloc'd or (recently) free'd
name2utf8() returns newly allocated memory which needs to be freed.
Error: RESOURCE_LEAK (CWE-772): [#def27] [important]
monitor/att.c:2291:2: alloc_fn: Storage is returned from allocation function "name2utf8".
monitor/att.c:2291:2: var_assign: Assigning: "name" = storage returned from "name2utf8((uint8_t *)frame->data, frame->size)".
monitor/att.c:2293:2: noescape: Resource "name" is not freed or pointed-to in "printf". [Note: The source code implementation of the function has been overridden by a builtin model.]
monitor/att.c:2294:1: leaked_storage: Variable "name" going out of scope leaks the storage it points to.
2292|
2293| print_field(" Media Player Name: %s", name);
2294|-> }
2295|
2296| static void mp_name_read(const struct l2cap_frame *frame)
Error: RESOURCE_LEAK (CWE-772): [#def28] [important]
monitor/att.c:2320:2: alloc_fn: Storage is returned from allocation function "name2utf8".
monitor/att.c:2320:2: var_assign: Assigning: "name" = storage returned from "name2utf8((uint8_t *)frame->data, frame->size)".
monitor/att.c:2322:2: noescape: Resource "name" is not freed or pointed-to in "printf". [Note: The source code implementation of the function has been overridden by a builtin model.]
monitor/att.c:2323:1: leaked_storage: Variable "name" going out of scope leaks the storage it points to.
2321|
2322| print_field(" Track Title: %s", name);
2323|-> }
2324|
2325| static void track_title_read(const struct l2cap_frame *frame)
Error: RESOURCE_LEAK (CWE-772): [#def29] [important]
monitor/att.c:2453:2: alloc_fn: Storage is returned from allocation function "name2utf8".
monitor/att.c:2453:2: var_assign: Assigning: "name" = storage returned from "name2utf8((uint8_t *)frame->data, frame->size)".
monitor/att.c:2455:2: noescape: Resource "name" is not freed or pointed-to in "printf". [Note: The source code implementation of the function has been overridden by a builtin model.]
monitor/att.c:2456:1: leaked_storage: Variable "name" going out of scope leaks the storage it points to.
2454|
2455| print_field(" Bearer Name: %s", name);
2456|-> }
2457|
2458| static void bearer_name_read(const struct l2cap_frame *frame)
Error: RESOURCE_LEAK (CWE-772): [#def30] [important]
monitor/att.c:2472:2: alloc_fn: Storage is returned from allocation function "name2utf8".
monitor/att.c:2472:2: var_assign: Assigning: "name" = storage returned from "name2utf8((uint8_t *)frame->data, frame->size)".
monitor/att.c:2474:2: noescape: Resource "name" is not freed or pointed-to in "printf". [Note: The source code implementation of the function has been overridden by a builtin model.]
monitor/att.c:2475:1: leaked_storage: Variable "name" going out of scope leaks the storage it points to.
2473|
2474| print_field(" Bearer Uci Name: %s", name);
2475|-> }
2476|
2477| static void print_technology_name(const struct l2cap_frame *frame)
Error: RESOURCE_LEAK (CWE-772): [#def31] [important]
monitor/att.c:2541:2: alloc_fn: Storage is returned from allocation function "name2utf8".
monitor/att.c:2541:2: var_assign: Assigning: "name" = storage returned from "name2utf8((uint8_t *)frame->data, frame->size)".
monitor/att.c:2543:2: noescape: Resource "name" is not freed or pointed-to in "printf". [Note: The source code implementation of the function has been overridden by a builtin model.]
monitor/att.c:2544:1: leaked_storage: Variable "name" going out of scope leaks the storage it points to.
2542|
2543| print_field(" Uri scheme Name: %s", name);
2544|-> }
2545|
2546| static void bearer_uri_schemes_list_read(const struct l2cap_frame *frame)
Error: RESOURCE_LEAK (CWE-772): [#def32] [important]
monitor/att.c:2653:2: alloc_fn: Storage is returned from allocation function "name2utf8".
monitor/att.c:2653:2: var_assign: Assigning: "call_uri" = storage returned from "name2utf8((uint8_t *)frame->data, frame->size)".
monitor/att.c:2655:2: noescape: Resource "call_uri" is not freed or pointed-to in "printf". [Note: The source code implementation of the function has been overridden by a builtin model.]
monitor/att.c:2660:1: leaked_storage: Variable "call_uri" going out of scope leaks the storage it points to.
2658| if (frame->size)
2659| print_hex_field(" call_list Data", frame->data, frame->size);
2660|-> }
2661|
2662| static void bearer_current_call_list_read(const struct l2cap_frame *frame)
Error: RESOURCE_LEAK (CWE-772): [#def33] [important]
monitor/att.c:2741:2: alloc_fn: Storage is returned from allocation function "name2utf8".
monitor/att.c:2741:2: var_assign: Assigning: "name" = storage returned from "name2utf8((uint8_t *)frame->data, frame->size)".
monitor/att.c:2743:2: noescape: Resource "name" is not freed or pointed-to in "printf". [Note: The source code implementation of the function has been overridden by a builtin model.]
monitor/att.c:2748:1: leaked_storage: Variable "name" going out of scope leaks the storage it points to.
2746| if (frame->size)
2747| print_hex_field(" Data", frame->data, frame->size);
2748|-> }
2749|
2750| static void incom_target_bearer_uri_read(const struct l2cap_frame *frame)
Error: RESOURCE_LEAK (CWE-772): [#def34] [important]
monitor/att.c:2851:3: alloc_fn: Storage is returned from allocation function "name2utf8".
monitor/att.c:2851:3: var_assign: Assigning: "name" = storage returned from "name2utf8((uint8_t *)frame->data, frame->size)".
monitor/att.c:2852:3: noescape: Resource "name" is not freed or pointed-to in "printf". [Note: The source code implementation of the function has been overridden by a builtin model.]
monitor/att.c:2871:1: leaked_storage: Variable "name" going out of scope leaks the storage it points to.
2869| if (frame->size)
2870| print_hex_field("call_cp Data", frame->data, frame->size);
2871|-> }
2872|
2873| static void print_call_cp_notification(const struct l2cap_frame *frame)
Error: RESOURCE_LEAK (CWE-772): [#def35] [important]
monitor/att.c:3046:2: alloc_fn: Storage is returned from allocation function "name2utf8".
monitor/att.c:3046:2: var_assign: Assigning: "name" = storage returned from "name2utf8((uint8_t *)frame->data, frame->size)".
monitor/att.c:3048:2: noescape: Resource "name" is not freed or pointed-to in "printf". [Note: The source code implementation of the function has been overridden by a builtin model.]
monitor/att.c:3053:1: leaked_storage: Variable "name" going out of scope leaks the storage it points to.
3051| if (frame->size)
3052| print_hex_field(" Data", frame->data, frame->size);
3053|-> }
3054|
3055| static void incoming_call_read(const struct l2cap_frame *frame)
Error: RESOURCE_LEAK (CWE-772): [#def36] [important]
monitor/att.c:3077:2: alloc_fn: Storage is returned from allocation function "name2utf8".
monitor/att.c:3077:2: var_assign: Assigning: "name" = storage returned from "name2utf8((uint8_t *)frame->data, frame->size)".
monitor/att.c:3079:2: noescape: Resource "name" is not freed or pointed-to in "printf". [Note: The source code implementation of the function has been overridden by a builtin model.]
monitor/att.c:3084:1: leaked_storage: Variable "name" going out of scope leaks the storage it points to.
3082| if (frame->size)
3083| print_hex_field(" Data", frame->data, frame->size);
3084|-> }
3085|
3086| static void call_friendly_name_read(const struct l2cap_frame *frame)
gatt_db_service_insert_characteristic shall not attempt to insert the
characteristic attribute handle on the next available index as there
could be descriptors in between so this changes the way
get_attribute_index calculates the index based on the given handle to
properly skip indexes used by descriptors.
This attempts to insert discovered attributes into monitor gatt_db
instance if their respective discover procedures are used which enables
decoding traces injected by user via unit testing:
> sudo unit/test-bap -m -s "34
= test-bap: BAP/UCL/SCC/BV-034-C [UCL SNK Config Codec, VS] - run
> test-bap: User Data RX
ATT: Read Request (0x0a) len 2
Handle: 0x0003 Type: Sink PAC (0x2bc9)
< test-bap: User Data TX
ATT: Read Response (0x0b) len 8
Handle: 0x0003 Type: Sink PAC (0x2bc9)
Value: 01ff010001000000
Number of PAC(s): 1
PAC #0:
Codec: Vendor specific (0xff)
Codec Company ID: Nokia Mobile Phones (0x0001)
Codec Vendor ID: 0x0001
> test-bap: User Data RX
ATT: Read Request (0x0a) len 2
Handle: 0x0006 Type: Sink Audio Locations (0x2bca)
< test-bap: User Data TX
ATT: Read Response (0x0b) len 4
Handle: 0x0006 Type: Sink Audio Locations (0x2bca)
Value: 03000000
Location: 0x00000003
Front Left (0x00000001)
Front Right (0x00000002)
> test-bap: User Data RX
ATT: Read Request (0x0a) len 2
Handle: 0x0009 Type: Source PAC (0x2bcb)
< test-bap: User Data TX
ATT: Read Response (0x0b) len 8
Handle: 0x0009 Type: Source PAC (0x2bcb)
Value: 01ff010001000000
Number of PAC(s): 1
PAC #0:
Codec: Vendor specific (0xff)
Codec Company ID: Nokia Mobile Phones (0x0001)
Codec Vendor ID: 0x0001
> test-bap: User Data RX
ATT: Read Request (0x0a) len 2
Handle: 0x000c Type: Source Audio Locations (0x2bcc)
< test-bap: User Data TX
ATT: Read Response (0x0b) len 4
Handle: 0x000c Type: Source Audio Locations (0x2bcc)
Value: 03000000
Location: 0x00000003
Front Left (0x00000001)
Front Right (0x00000002)
> test-bap: User Data RX
ATT: Read Request (0x0a) len 2
Handle: 0x000f Type: Available Audio Contexts (0x2bcd)
< test-bap: User Data TX
ATT: Read Response (0x0b) len 4
Handle: 0x000f Type: Available Audio Contexts (0x2bcd)
Value: ff0f0e00
Sink Context: 0x0fff
Unspecified (0x0001)
Conversational (0x0002)
Media (0x0004)
Game (0x0008)
Instructional (0x0010)
Voice Assistants (0x0020)
Live (0x0040)
Sound Effects (0x0080)
Notifications (0x0100)
Ringtone (0x0200)
Alerts (0x0400)
Emergency alarm (0x0800)
Source Context: 0x000e
Conversational (0x0002)
Media (0x0004)
Game (0x0008)
> test-bap: User Data RX
ATT: Read Request (0x0a) len 2
Handle: 0x0012 Type: Supported Audio Contexts (0x2bce)
< test-bap: User Data TX
ATT: Read Response (0x0b) len 4
Handle: 0x0012 Type: Supported Audio Contexts (0x2bce)
Value: ff0f0e00
Sink Context: 0x0fff
Unspecified (0x0001)
Conversational (0x0002)
Media (0x0004)
Game (0x0008)
Instructional (0x0010)
Voice Assistants (0x0020)
Live (0x0040)
Sound Effects (0x0080)
Notifications (0x0100)
Ringtone (0x0200)
Alerts (0x0400)
Emergency alarm (0x0800)
Source Context: 0x000e
Conversational (0x0002)
Media (0x0004)
Game (0x0008)
> test-bap: User Data RX
ATT: Read Request (0x0a) len 2
Handle: 0x0016 Type: Sink ASE (0x2bc4)
< test-bap: User Data TX
ATT: Read Response (0x0b) len 2
Handle: 0x0016 Type: Sink ASE (0x2bc4)
Value: 0100
ASE ID: 1
State: Idle (0x00)
> test-bap: User Data RX
ATT: Write Request (0x12) len 4
Handle: 0x0017
Data: 0100
< test-bap: User Data TX
ATT: Write Response (0x13) len 0
> test-bap: User Data RX
ATT: Read Request (0x0a) len 2
Handle: 0x0019 Type: Sink ASE (0x2bc4)
< test-bap: User Data TX
ATT: Read Response (0x0b) len 2
Handle: 0x0019 Type: Sink ASE (0x2bc4)
Value: 0200
ASE ID: 2
State: Idle (0x00)
> test-bap: User Data RX
ATT: Write Request (0x12) len 4
Handle: 0x001a
Data: 0100
< test-bap: User Data TX
ATT: Write Response (0x13) len 0
> test-bap: User Data RX
ATT: Read Request (0x0a) len 2
Handle: 0x001c Type: Source ASE (0x2bc5)
< test-bap: User Data TX
ATT: Read Response (0x0b) len 2
Handle: 0x001c Type: Source ASE (0x2bc5)
Value: 0300
ASE ID: 3
State: Idle (0x00)
> test-bap: User Data RX
ATT: Write Request (0x12) len 4
Handle: 0x001d
Data: 0100
< test-bap: User Data TX
ATT: Write Response (0x13) len 0
> test-bap: User Data RX
ATT: Read Request (0x0a) len 2
Handle: 0x001f Type: Source ASE (0x2bc5)
< test-bap: User Data TX
ATT: Read Response (0x0b) len 2
Handle: 0x001f Type: Source ASE (0x2bc5)
Value: 0400
ASE ID: 4
State: Idle (0x00)
> test-bap: User Data RX
ATT: Write Request (0x12) len 4
Handle: 0x0020
Data: 0100
< test-bap: User Data TX
ATT: Write Response (0x13) len 0
> test-bap: User Data RX
ATT: Write Request (0x12) len 4
Handle: 0x0023
Data: 0100
< test-bap: User Data TX
ATT: Write Response (0x13) len 0
> test-bap: User Data RX
ATT: Write Command (0x52) len 13
Handle: 0x0022 Type: ASE Control Point (0x2bc6)
Data: 0101030202ff0100010000
Opcode: Codec Configuration (0x01)
Number of ASE(s): 1
ASE: #0
ASE ID: 0x03
Target Latency: Balance Latency/Reliability (0x02)
PHY: 0x02
LE 2M PHY (0x02)
Codec: Vendor specific (0xff)
Codec Company ID: Nokia Mobile Phones (0x0001)
Codec Vendor ID: 0x0001
< test-bap: User Data TX
ATT: Handle Value Notification (0x1b) len 7
Handle: 0x0022 Type: ASE Control Point (0x2bc6)
Data: 0101030000
Opcode: Codec Configuration (0x01)
Number of ASE(s): 1
ASE: #0
ASE ID: 0x03
ASE Response Code: Success (0x00)
ASE Response Reason: None (0x00)
< test-bap: User Data TX
ATT: Handle Value Notification (0x1b) len 27
Handle: 0x001c Type: Source ASE (0x2bc5)
Data: 03010102010a00204e00409c00204e00409c00ff0100010000
ASE ID: 3
State: Codec Configured (0x01)
Framing: Unframed PDUs not supported (0x01)
PHY: 0x02
LE 2M PHY preffered (0x02)
RTN: 1
Max Transport Latency: 10
Presentation Delay Min: 20000 us
Presentation Delay Max: 40000 us
Preferred Presentation Delay Min: 20000 us
Preferred Presentation Delay Max: 40000 us
Codec: Vendor specific (0xff)
Codec Company ID: Nokia Mobile Phones (0x0001)
Codec Vendor ID: 0x0001
Device using RPA have its storage using its identity address so this
uses keys_resolve_identity to attempt to resolve the destination
address instead of always using the connection address.
This prints the value attribute information when print attribute
descriptors:
< ACL Data TX: Handle 3585 flags 0x00 dlen 9
ATT: Write Request (0x12) len 4
Handle: 0x002c Type: Client Characteristic Configuration (0x2902)
Value Handle: 0x002b Type: Battery Level (0x2a19)
Data: 0100
Notification (0x01)
Data field were print twice (1 time incorrectly):
> ACL Data RX: Handle 64 flags 0x02 dlen 19
ATT: Signed Write Command (0xd2) len 14
Handle: 0x006f Type: Vendor specific (f7debc9a-7856-3412-7856-341278563412)
Data: 0800000087f303c224516133
Data:
Signature: 0800000087f303c224516133
According to CSIS specification v1.0.1: "Allowed values for the Set
Member Lock characteristic are Unlocked (corresponding to the
numeric value 0x01) and Locked (corresponding to the numeric
value 0x02); all other values are RFU".
If a read/read by type fails it needs to be dequeued otherwise it can
cause the next operation of the same type to return the wrong request
and possible decoding as if it was a different attribute type.
Notification/Indication shall be treated as response (rsp=true) so the
correct database is used:
> ACL Data RX: Handle 3585 flags 0x02 dlen 14
ATT: Handle Value Notification (0x1b) len 9
Handle: 0x002a Type: Report (0x2a4d)
Data: 0000feffff0000
This fixes the following error:
monitor/att.c: In function 'print_attribute':
monitor/att.c:1850:35: error: lvalue required as unary '&' operand
print_uuid(label, &cpu_to_le16(uuid->value.u16), 2);
This prints the attribute information on ATT_REQ_RSP to make it easier
to identify to which handle the response is for:
> ACL Data RX: Handle 42 flags 0x02 dlen 9
Channel: 65 len 5 sdu 3 [PSM 39 mode Enhanced Credit (0x81)] {chan 1}
ATT: Read Response (0x0b) len 2
Value: 0300
Handle: 0x0030 Type: Source ASE (0x2bc5)
ASE ID: 3
State: Idle (0x00)
This stops calling hci_devba everytime the GATT db needs to be loaded
since that causes a raw socket to be open to read back the address
pointed by the index, instead this is done only once at assign_handle
and store in packet_conn_data.
This adds decoding support for PAC Sink/Source attributes:
< ACL Data TX: Handle 42 flags 0x00 dlen 9
Channel: 64 len 5 sdu 3 [PSM 39 mode Enhanced Credit (0x81)]
{chan 0}
ATT: Read Request (0x0a) len 2
Handle: 0x0017 Type: Sink PAC (0x2bc9)
> ACL Data RX: Handle 42 flags 0x02 dlen 31
Channel: 65 len 27 sdu 25 [PSM 39 mode Enhanced Credit (0x81)]
{chan 0}
Value: 010600000000100301ff0002020302030305041e00f00000
Number of PAC(s): 1
PAC #0:
Codec: LC3 (0x06)
Codec Specific Configuration #0: len 0x03 type 0x01
Codec Specific Configuration: ff00
Codec Specific Configuration #1: len 0x02 type 0x02
Codec Specific Configuration: 03
Codec Specific Configuration #2: len 0x02 type 0x03
Codec Specific Configuration: 03
Codec Specific Configuration #3: len 0x05 type 0x04
Codec Specific Configuration: 1e00f000
If there are multiple notifications in the same frame the callback may
alter it when using l2cap_frame_pull helpers, so instead this passes a
cloned frame with just the expected length so callbacks cannot alter
original frame.
This attempt to decode the attribute type if its gatt_db can be loaded:
< ACL Data TX: Handle 3585 flags 0x00 dlen 9
ATT: Write Request (0x12) len 4
Handle: 0x000b Type: Client Characteristic Configuration (0x2902)
Data: 0200