From patchwork Fri Jun 17 00:49:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Augusto von Dentz X-Patchwork-Id: 584275 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 06C52C43334 for ; Fri, 17 Jun 2022 00:50:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233134AbiFQAuC (ORCPT ); Thu, 16 Jun 2022 20:50:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58240 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229734AbiFQAuB (ORCPT ); Thu, 16 Jun 2022 20:50:01 -0400 Received: from mail-pj1-x102b.google.com (mail-pj1-x102b.google.com [IPv6:2607:f8b0:4864:20::102b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 39B2F61636 for ; Thu, 16 Jun 2022 17:50:00 -0700 (PDT) Received: by mail-pj1-x102b.google.com with SMTP id b12-20020a17090a6acc00b001ec2b181c98so1644292pjm.4 for ; Thu, 16 Jun 2022 17:50:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=G9oieWRgAMAuM4l/LZD5hLljgu0Jll3/4JXTYS8AOqs=; b=KDuXlmBRKFQLY+EP+L+C+EVf/tP92F17XG3lO3/AnGA0gyOnvbuphQ1V0v+aqqXtoa cnclYGryu1oN/ELK4gzT/+4WEO+paLvyP8z2lAcrw4sX4IP2zkNaCZ0kXvcYTnOumk/P IKt5I7bIAX4oCKutCXtfVgC0LUZ5xOwZbqhq/C8uIU31GUwxmtpX31bQYthmv4rjDHmD LF1TjqAyO0uTTL4N9Pfv9yckAA8AByCpda56uZNGUghHfKhYNe4gMktW3hf6mb2uq0q+ yp0Tdcesk/HF6cUxDiEgPT+rwfpp5/nRPj/jGXnhoU69a0hX6GgQRA382D1K9Ca4T1wI 3vQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=G9oieWRgAMAuM4l/LZD5hLljgu0Jll3/4JXTYS8AOqs=; b=flauQHTP1trNnldcVLWzpNbW+DqegQ4XxZhNtY/zBLEktUJt5CxrZ7sYh+f2E8MpAx JrVVkFJeblA+vjfwf2L8pUE2q8SarXTQbVt9lR6kXkBhveUyIpCE59w1Jpc2m6K7BmB4 Z/2WKd3q3cVZ7fw6jT05Boxm8MvUjWfQ4Eg3WcnUhvjZ5cU6RIt3n8EYGSxHxnJ2cWZV p+eiPY9HJb12tBna7koZqBvm3W+4NOhyl7lK4Ho8pxr0Up4GGCzWlpqbfGCKCtXPQaQI kGIVI8/bkXQm/pNp4z3XDMGnBRO2aNuklQ2+l/tOe7KJWK8Ipxlz/n0CpQUmFTLJbxS9 bJgQ== X-Gm-Message-State: AJIora++rW4DHk9WcZtVtVRus5i4382WL1U6qVlcO76JH1FESbVz9t9t +UEO4D3YyX6PQa/yx4F3XP9TLYsHELQ= X-Google-Smtp-Source: AGRyM1tdEFJ727Olc95ciGixXINdYZ27LdnxBbo5RhQFlxmBz0CuYUhRANWtqUwQe6PCIGE4dLfDuw== X-Received: by 2002:a17:902:728d:b0:168:d0cf:2246 with SMTP id d13-20020a170902728d00b00168d0cf2246mr6947778pll.74.1655426999174; Thu, 16 Jun 2022 17:49:59 -0700 (PDT) Received: from lvondent-mobl4.. (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id u23-20020a170902a61700b0015e8d4eb25asm338996plq.164.2022.06.16.17.49.58 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jun 2022 17:49:58 -0700 (PDT) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ 1/4] monitor/att: Print attribute information on ATT_REQ_RSP Date: Thu, 16 Jun 2022 17:49:54 -0700 Message-Id: <20220617004957.1148939-1-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.35.3 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz 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) --- monitor/att.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/monitor/att.c b/monitor/att.c index de70a9dc4..34babac6b 100644 --- a/monitor/att.c +++ b/monitor/att.c @@ -1290,17 +1290,12 @@ static struct gatt_db_attribute *get_attribute(const struct l2cap_frame *frame, return gatt_db_get_attribute(db, handle); } -static void print_handle(const struct l2cap_frame *frame, uint16_t handle, - bool rsp) +static void print_attribute(struct gatt_db_attribute *attr) { - struct gatt_db_attribute *attr; + uint16_t handle = gatt_db_attribute_get_handle(attr); const bt_uuid_t *uuid; char label[21]; - attr = get_attribute(frame, handle, rsp); - if (!attr) - goto done; - uuid = gatt_db_attribute_get_type(attr); if (!uuid) goto done; @@ -1323,6 +1318,20 @@ done: print_field("Handle: 0x%4.4x", handle); } +static void print_handle(const struct l2cap_frame *frame, uint16_t handle, + bool rsp) +{ + struct gatt_db_attribute *attr; + + attr = get_attribute(frame, handle, rsp); + if (!attr) { + print_field("Handle: 0x%4.4x", handle); + return; + } + + print_attribute(attr); +} + static void att_read_req(const struct l2cap_frame *frame) { const struct bt_l2cap_att_read_req *pdu = frame->data; @@ -1393,6 +1402,8 @@ static void att_read_rsp(const struct l2cap_frame *frame) if (!read) return; + print_attribute(read->attr); + read->func(frame); free(read); From patchwork Fri Jun 17 00:49:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Augusto von Dentz X-Patchwork-Id: 582614 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E30EBC433EF for ; Fri, 17 Jun 2022 00:50:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233339AbiFQAuE (ORCPT ); Thu, 16 Jun 2022 20:50:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58246 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232424AbiFQAuC (ORCPT ); Thu, 16 Jun 2022 20:50:02 -0400 Received: from mail-pj1-x1034.google.com (mail-pj1-x1034.google.com [IPv6:2607:f8b0:4864:20::1034]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 755EA62215 for ; Thu, 16 Jun 2022 17:50:01 -0700 (PDT) Received: by mail-pj1-x1034.google.com with SMTP id t3-20020a17090a510300b001ea87ef9a3dso2855352pjh.4 for ; Thu, 16 Jun 2022 17:50:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=quKHrfAloY3WsrO87VOSJq46tjw5gmCo6dq5cjf6nDg=; b=QDMv41xbXX/1q9DMnknODD8mDoTTdppB8/ixPgsQ2sQXVoSbsxv4TBuWTQa3NUryp3 9I6LlCP5CQP6D7Q1IK40XtYE8uOpqeU2OJ6RrWUyxxuxxtePWNpMDNDkrioTqXEjbbj7 NLN6lkZr6jrjggMRhl71gQUy4yl29jdEybEPLfZjqu9vw+hAF7ltQ4mEEisYt8PGA0uY +u9iYD9KDPCLDBMCnZFhFzlk0il3BRuMW6Zq8pk+KgmsfgQPSAxeqy4EVciqrpNpKwYq tW1BRRm8Vtn0gtS97dNwe0f7aaa7XblzohNWJzqevkQyxjQlqwRmUQvA2HCN672mlygn indQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=quKHrfAloY3WsrO87VOSJq46tjw5gmCo6dq5cjf6nDg=; b=t5QO+7LGg0HH06r73EB6vPgcSyEmtCEKSkBsiehiQPHuksZJi38FlOS3YpQDT1HjeQ i/c13KtP4lEQTWQpUALKBHNdNqiRxoXvH6Dmgdc6SFrWJkFlerCKfL1ZLGL3ZGvj+nNY X7sEFn0wKG416vSzvqpRyiTPBS9evGqT7fYOG5bb3BV0SSOSeZpfppk1CTk91N+QWZRc rc8UsaCUq65vtxjftR42pEdOFEXKWjcYcmdyvT4vyZ3H+e1WsP7S/778onMknvwKpveP MK9/+N0l4mS9N0lYXUAA9PQypSqFXRk2QshReaJrxSZWG/jo+asWvUIv7gVzDvN42Ewh /3Uw== X-Gm-Message-State: AJIora90chdfzgC5w58Mnfb8yGi/nqk450wcWVvHYduhn2LuAR8+04dQ UQEG8CtqhUtHXHgA4nBZ3AkjI5fVe60= X-Google-Smtp-Source: AGRyM1vgd7anUgQRcZDJ62THgYGJivBuBB0gPSiVeCafTCtNowaiGAquIRkSv/Yvhj9ngi7YwVUeVg== X-Received: by 2002:a17:902:7102:b0:168:dcbe:7c50 with SMTP id a2-20020a170902710200b00168dcbe7c50mr7263151pll.116.1655427000402; Thu, 16 Jun 2022 17:50:00 -0700 (PDT) Received: from lvondent-mobl4.. (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id u23-20020a170902a61700b0015e8d4eb25asm338996plq.164.2022.06.16.17.49.59 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jun 2022 17:49:59 -0700 (PDT) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ 2/4] monitor/att: Add decoding support for PAC Sink/Source Location Date: Thu, 16 Jun 2022 17:49:55 -0700 Message-Id: <20220617004957.1148939-2-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20220617004957.1148939-1-luiz.dentz@gmail.com> References: <20220617004957.1148939-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz This adds decoding support for PAC Sink/Source Location attributes: > 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 Request (0x0a) len 2 Handle: 0x001a Type: Sink Audio Locations (0x2bca) < ACL Data TX: Handle 42 flags 0x00 dlen 11 Channel: 64 len 7 sdu 5 [PSM 39 mode Enhanced Credit (0x81)] {chan 1} ATT: Read Response (0x0b) len 4 Value: 03000000 Handle: 0x001a Type: Sink Audio Locations (0x2bca) Location: 0x00000003 Front Left (0x00000001) Front Right (0x00000002) --- monitor/att.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/monitor/att.c b/monitor/att.c index 34babac6b..8b47cbd9f 100644 --- a/monitor/att.c +++ b/monitor/att.c @@ -1050,6 +1050,74 @@ static void ase_cp_notify(const struct l2cap_frame *frame) print_ase_cp_rsp(frame); } +static const struct bitfield_data pac_loc_table[] = { + { 0, "Front Left (0x00000001)" }, + { 1, "Front Right (0x00000002)" }, + { 2, "Front Center (0x00000004)" }, + { 3, "Low Frequency Effects 1 (0x00000008)" }, + { 4, "Back Left (0x00000010)" }, + { 5, "Back Right (0x00000020)" }, + { 6, "Front Left of Center (0x00000040)" }, + { 7, "Front Right of Center (0x00000080)" }, + { 8, "Back Center (0x00000100)" }, + { 9, "Low Frequency Effects 2 (0x00000200)" }, + { 10, "Side Left (0x00000400)" }, + { 11, "Side Right (0x00000800)" }, + { 12, "Top Front Left (0x00001000)" }, + { 13, "Top Front Right (0x00002000)" }, + { 14, "Top Front Center (0x00004000)" }, + { 15, "Top Center (0x00008000)" }, + { 16, "Top Back Left (0x00010000)" }, + { 17, "Top Back Right (0x00020000)" }, + { 18, "Top Side Left (0x00040000)" }, + { 19, "Top Side Right (0x00080000)" }, + { 20, "Top Back Center (0x00100000)" }, + { 21, "Bottom Front Center (0x00200000)" }, + { 22, "Bottom Front Left (0x00400000)" }, + { 23, "Bottom Front Right (0x00800000)" }, + { 24, "Front Left Wide (0x01000000)" }, + { 25, "Front Right Wide (0x02000000)" }, + { 26, "Left Surround (0x04000000)" }, + { 27, "Right Surround (0x08000000)" }, + { 28, "RFU (0x10000000)" }, + { 29, "RFU (0x20000000)" }, + { 30, "RFU (0x40000000)" }, + { 31, "RFU (0x80000000)" }, + { } +}; + +static void print_loc_pac(const struct l2cap_frame *frame) +{ + uint32_t value; + uint8_t mask; + + if (!l2cap_frame_get_le32((void *)frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Location: 0x%8.8x", value); + + mask = print_bitfield(4, value, pac_loc_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)", + mask); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void pac_loc_read(const struct l2cap_frame *frame) +{ + print_loc_pac(frame); +} + +static void pac_loc_notify(const struct l2cap_frame *frame) +{ + print_loc_pac(frame); +} + #define GATT_HANDLER(_uuid, _read, _write, _notify) \ { \ .uuid = { \ @@ -1072,7 +1140,9 @@ struct gatt_handler { GATT_HANDLER(0x2bc5, ase_read, NULL, ase_notify), GATT_HANDLER(0x2bc6, NULL, ase_cp_write, ase_cp_notify), GATT_HANDLER(0x2bc9, pac_read, NULL, pac_notify), + GATT_HANDLER(0x2bca, pac_loc_read, NULL, pac_loc_notify), GATT_HANDLER(0x2bcb, pac_read, NULL, pac_notify), + GATT_HANDLER(0x2bcc, pac_loc_read, NULL, pac_loc_notify), }; static struct gatt_handler *get_handler(struct gatt_db_attribute *attr) From patchwork Fri Jun 17 00:49:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Augusto von Dentz X-Patchwork-Id: 584274 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 197E9C43334 for ; Fri, 17 Jun 2022 00:50:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237138AbiFQAuF (ORCPT ); Thu, 16 Jun 2022 20:50:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58254 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229734AbiFQAuD (ORCPT ); Thu, 16 Jun 2022 20:50:03 -0400 Received: from mail-pj1-x102b.google.com (mail-pj1-x102b.google.com [IPv6:2607:f8b0:4864:20::102b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8AD4761636 for ; Thu, 16 Jun 2022 17:50:02 -0700 (PDT) Received: by mail-pj1-x102b.google.com with SMTP id b12-20020a17090a6acc00b001ec2b181c98so1644292pjm.4 for ; Thu, 16 Jun 2022 17:50:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=ngvRkXqu/S3FB6n+X5RMXZi32SU2C1O7n4EzOBlNzLo=; b=ptALWP4VzR+cziSAJYBLWI2JgXI3DaOjRqxfvIw0+0u/H+BVWRMtsmNE3aDQc2I+3t UWoN3hBFb1RNbIW2Q9oksKAREky8E7ltxoX5upstKFqLgTCgLyysvoQ5SDNTIJVkmUZ8 qGuGSWNlVTl77UPrBPaQTEC0IermFBBvcyycsUg6czNAYwcahVgDsrLfJesNmb4HlhU6 hPU65/n5eDHYs5zWKDC49I1Ha/peVGA5XwypFoJM9zfm3sqTNDr2+M008wk4bxcHQAXv RSrWqfFIQDaHUDSZlZFnMxzpIO41oIZS9TP0beHJpGZLfFsqhvnWpXcV5a83DK86u80M 13Tw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ngvRkXqu/S3FB6n+X5RMXZi32SU2C1O7n4EzOBlNzLo=; b=fntzP3ODurIZEoJG9MjUV1ku0SjeyMZ2cqhT5r6q2l0VrvMxHA7DzbghKxPo4oR7pU Kdv4YD8XzLBrPs5Nj5i8TsZRhta9rbbXJ/+VpnP/4qGgeZ8dhRknrlkMhjb721+qL6zx FeJMh6aTjDqC13EXQa/f7POnJneU0pH+C5PXCtjrXtYZP4M0hKjYDxZfhQjn8XT4NKrp ZicRW+Ya3uXgkIcV3ylBGsD5oGYDLIVqvCjsY0i0g6TygRU7tyT+7qNXY0XHW3vBxgMI gOPQogVJpNOLhuCxx8OBfAUaiqgd/h+16Jl7J95msE2X+l6WHwHlVNR03TeIFVITCx8E uQog== X-Gm-Message-State: AJIora9DC4XA60hRAbo11MLLddxFTGA0wgvBJamogSs9+AREo3Yd9or5 e5vojEZ9hQ+YHE9lJ2zJl2a5qL5f0dU= X-Google-Smtp-Source: AGRyM1tkJpdF4yt9n4M+Db8p6n8EgLU2aYJbLGTv+bV5xL5O2ejBoqOBh1BZ+5SftcqnsEplOTBQnQ== X-Received: by 2002:a17:902:b218:b0:168:de55:dfba with SMTP id t24-20020a170902b21800b00168de55dfbamr6995636plr.134.1655427001685; Thu, 16 Jun 2022 17:50:01 -0700 (PDT) Received: from lvondent-mobl4.. (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id u23-20020a170902a61700b0015e8d4eb25asm338996plq.164.2022.06.16.17.50.00 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jun 2022 17:50:00 -0700 (PDT) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ 3/4] monitor/att: Add decoding support for PAC Audio Context Date: Thu, 16 Jun 2022 17:49:56 -0700 Message-Id: <20220617004957.1148939-3-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20220617004957.1148939-1-luiz.dentz@gmail.com> References: <20220617004957.1148939-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz This adds decoding support for PAC Audio Context attributes: > 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 Request (0x0a) len 2 Handle: 0x0026 Type: Supported Audio Contexts (0x2bce) < ACL Data TX: Handle 42 flags 0x00 dlen 11 Channel: 64 len 7 sdu 5 [PSM 39 mode Enhanced Credit (0x81)] {chan 1} ATT: Read Response (0x0b) len 4 Value: ff0f0e00 Handle: 0x0026 Type: Supported Audio Contexts (0x2bce) 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) --- monitor/att.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/monitor/att.c b/monitor/att.c index 8b47cbd9f..21fa5dde3 100644 --- a/monitor/att.c +++ b/monitor/att.c @@ -1118,6 +1118,69 @@ static void pac_loc_notify(const struct l2cap_frame *frame) print_loc_pac(frame); } +static const struct bitfield_data pac_context_table[] = { + { 0, "Unspecified (0x0001)" }, + { 1, "Conversational (0x0002)" }, + { 2, "Media (0x0004)" }, + { 3, "Game (0x0008)" }, + { 4, "Instructional (0x0010)" }, + { 5, "Voice Assistants (0x0020)" }, + { 6, "Live (0x0040)" }, + { 7, "Sound Effects (0x0080)" }, + { 8, "Notifications (0x0100)" }, + { 9, "Ringtone (0x0200)" }, + { 10, "Alerts (0x0400)" }, + { 11, "Emergency alarm (0x0800)" }, + { 12, "RFU (0x1000)" }, + { 13, "RFU (0x2000)" }, + { 14, "RFU (0x4000)" }, + { 15, "RFU (0x8000)" }, +}; + +static void print_pac_context(const struct l2cap_frame *frame) +{ + uint16_t snk, src; + uint16_t mask; + + if (!l2cap_frame_get_le16((void *)frame, &snk)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Sink Context: 0x%4.4x", snk); + + mask = print_bitfield(4, snk, pac_context_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", + mask); + + if (!l2cap_frame_get_le16((void *)frame, &src)) { + print_text(COLOR_ERROR, " sink: invalid size"); + goto done; + } + + print_field(" Source Context: 0x%4.4x", src); + + mask = print_bitfield(4, src, pac_context_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", + mask); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void pac_context_read(const struct l2cap_frame *frame) +{ + print_pac_context(frame); +} + +static void pac_context_notify(const struct l2cap_frame *frame) +{ + print_pac_context(frame); +} + #define GATT_HANDLER(_uuid, _read, _write, _notify) \ { \ .uuid = { \ @@ -1143,6 +1206,8 @@ struct gatt_handler { GATT_HANDLER(0x2bca, pac_loc_read, NULL, pac_loc_notify), GATT_HANDLER(0x2bcb, pac_read, NULL, pac_notify), GATT_HANDLER(0x2bcc, pac_loc_read, NULL, pac_loc_notify), + GATT_HANDLER(0x2bcd, pac_context_read, NULL, pac_context_notify), + GATT_HANDLER(0x2bce, pac_context_read, NULL, pac_context_notify), }; static struct gatt_handler *get_handler(struct gatt_db_attribute *attr) From patchwork Fri Jun 17 00:49:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Augusto von Dentz X-Patchwork-Id: 582613 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 79D9DCCA47A for ; Fri, 17 Jun 2022 00:50:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1378557AbiFQAuH (ORCPT ); Thu, 16 Jun 2022 20:50:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58284 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229734AbiFQAuG (ORCPT ); Thu, 16 Jun 2022 20:50:06 -0400 Received: from mail-pj1-x102e.google.com (mail-pj1-x102e.google.com [IPv6:2607:f8b0:4864:20::102e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 40D2762215 for ; Thu, 16 Jun 2022 17:50:04 -0700 (PDT) Received: by mail-pj1-x102e.google.com with SMTP id g10-20020a17090a708a00b001ea8aadd42bso2899543pjk.0 for ; Thu, 16 Jun 2022 17:50:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=CxF447mlSLUxV7Ha3XHfQCmc7Z5Nb0LFmJmey9zuRZ4=; b=WlG5hbeAVpKNNgGHaI6IGUqavNENot8TG9z03T4EQ9+3o7xUh81y+R/wPikz3RsKCG 5fvrHyyCPNsx6bALqKq47WAEzAgPLfT80lnhYE8+XscHCEfoZJPzWj1hPJ7vDOvzsGZ5 nhYvCA3bivOWYqtpEtd+Xz8iyDaageyAmshIhyDlP6SDkPg3ry/uxpPBYk9m+wR4yT5X BYOgDgLX0OZiJYqcfLiiwkkFeolsNrSriFKkoNzDmIpO42dmE4YPuVipDv8ZNVKwucFN d0XiQcXGKPjLsz3imMRgnIbfEw6HqVy5FULCbM+dis+FLEwhI20mWHw9dJGRz8XVRieJ 5Szw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CxF447mlSLUxV7Ha3XHfQCmc7Z5Nb0LFmJmey9zuRZ4=; b=WqTfjmZUZ0+KFYvhlnk/lUqTY3ESj+RmhchplZsO5SiBP0zV9AeSo9R+PsgvmQHCVV hTjFMxGQYH5O41jO/oHYqkx4tAPGwqcCELAGrSfhZyIKmDHfpOtLpwBSGBEMNbynhYpt WHLW2CPZsvG48l4nFmPRTdKD1xcFI0KBrM/5+R9U587oIVInUJdri1yCd09O8ZNH5QEN osyY3LJaQtn/yyE9wDXkG4jarIY1+0gi43x0Pe/O1aGu+JnAcadFNormLUUXVni16KeY kTJgu6zGVb3C5iNUc1XJ4zVk2bc7FWgIe4Y83GqU8NOBiB3IHw09N+bnq0nVtD7sL78o YJ1g== X-Gm-Message-State: AJIora+SzKlXdyuEEWl0lYoCDaOFqnmFT1zDpCLnGVI3zfzw/z2ya5wJ U0F6dVe6z62MF3pUrglGva/+m1ZT0Cg= X-Google-Smtp-Source: AGRyM1tzi890asZdPGTdFZvRH41Gb5tdICp9Is4QBS3FJqLWabl0LjoLUJ84EugkzSWc0WZcoBTnRQ== X-Received: by 2002:a17:90b:4b49:b0:1e6:8827:aaf1 with SMTP id mi9-20020a17090b4b4900b001e68827aaf1mr7766957pjb.154.1655427002896; Thu, 16 Jun 2022 17:50:02 -0700 (PDT) Received: from lvondent-mobl4.. (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id u23-20020a170902a61700b0015e8d4eb25asm338996plq.164.2022.06.16.17.50.01 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jun 2022 17:50:02 -0700 (PDT) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ 4/4] monitor/att: Add LTV deconding support for PAC/ASE Date: Thu, 16 Jun 2022 17:49:57 -0700 Message-Id: <20220617004957.1148939-4-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20220617004957.1148939-1-luiz.dentz@gmail.com> References: <20220617004957.1148939-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz This adds decoding support for PAC/ASE attributes: > ACL Data RX: Handle 42 flags 0x02 dlen 31 Channel: 65 len 27 sdu 25 [PSM 39 mode Enhanced Credit (0x81)] {chan 1} ATT: Read Response (0x0b) len 24 Value: 010600000000100301ff0002020302030305041e00f00000 Number of PAC(s): 1 PAC #0: Codec: LC3 (0x06) Codec Specific Capabilities #0: len 0x03 type 0x01 Sampling Frequencies: 0x00ff 8 Khz (0x0001) 11.25 Khz (0x0002) 16 Khz (0x0004) 22.05 Khz (0x0008) 24 Khz (0x0010) 32 Khz (0x0020) 44.1 Khz (0x0040) 48 Khz (0x0080) Codec Specific Capabilities #1: len 0x02 type 0x02 Frame Duration: 0x0003 7.5 ms (0x01) 10 ms (0x02) Codec Specific Capabilities #2: len 0x02 type 0x03 Audio Channel Count: 0x03 1 channel (0x01) 2 channels (0x02) Codec Specific Capabilities #3: len 0x05 type 0x04 Frame Length: 30 (0x001e) - 240 (0x00f0) > ACL Data RX: Handle 42 flags 0x02 dlen 30 Channel: 64 len 26 sdu 24 [PSM 39 mode Enhanced Credit (0x81)] {chan 0} ATT: Write Command (0x52) len 23 Handle: 0x0036 Type: ASE Control Point (0x2bc6) Data: 010101020206000000000a02010302020103042800 Opcode: Codec Configuration (0x01) Number of ASE(s): 1 ASE: #0 ASE ID: 0x01 Target Latency: Balance Latency/Reliability (0x02) PHY: 0x02 LE 2M PHY (0x02) Codec: LC3 (0x06) Codec Specific Configuration #0: len 0x02 type 0x01 Sampling Frequency: 16 Khz (0x03) Codec Specific Configuration #1: len 0x02 type 0x02 Frame Duration: 10 ms (0x01) Codec Specific Configuration #2: len 0x03 type 0x04 Frame Length: 40 (0x0028) --- monitor/att.c | 591 +++++++++++++++++++++++++++++++++++++++-------- monitor/packet.c | 39 +++- monitor/packet.h | 15 +- 3 files changed, 547 insertions(+), 98 deletions(-) diff --git a/monitor/att.c b/monitor/att.c index 21fa5dde3..7ab97c286 100644 --- a/monitor/att.c +++ b/monitor/att.c @@ -279,7 +279,8 @@ static bool print_ase_codec(const struct l2cap_frame *frame) return true; } -static bool print_ase_lv(const struct l2cap_frame *frame, const char *label) +static bool print_ase_lv(const struct l2cap_frame *frame, const char *label, + struct packet_ltv_decoder *decoder, size_t decoder_len) { struct bt_hci_lv_data *lv; @@ -294,21 +295,299 @@ static bool print_ase_lv(const struct l2cap_frame *frame, const char *label) return false; } - packet_print_ltv(label, lv->data, lv->len); + packet_print_ltv(label, lv->data, lv->len, decoder, decoder_len); return true; } -static bool print_ase_cc(const struct l2cap_frame *frame) +static bool print_ase_cc(const struct l2cap_frame *frame, const char *label, + struct packet_ltv_decoder *decoder, size_t decoder_len) { - return print_ase_lv(frame, " Codec Specific Configuration"); + return print_ase_lv(frame, label, decoder, decoder_len); } +static const struct bitfield_data pac_context_table[] = { + { 0, "Unspecified (0x0001)" }, + { 1, "Conversational (0x0002)" }, + { 2, "Media (0x0004)" }, + { 3, "Game (0x0008)" }, + { 4, "Instructional (0x0010)" }, + { 5, "Voice Assistants (0x0020)" }, + { 6, "Live (0x0040)" }, + { 7, "Sound Effects (0x0080)" }, + { 8, "Notifications (0x0100)" }, + { 9, "Ringtone (0x0200)" }, + { 10, "Alerts (0x0400)" }, + { 11, "Emergency alarm (0x0800)" }, + { 12, "RFU (0x1000)" }, + { 13, "RFU (0x2000)" }, + { 14, "RFU (0x4000)" }, + { 15, "RFU (0x8000)" }, + { } +}; + +static void print_context(const struct l2cap_frame *frame, const char *label) +{ + uint16_t value; + uint16_t mask; + + if (!l2cap_frame_get_le16((void *)frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field("%s: 0x%4.4x", label, value); + + mask = print_bitfield(8, value, pac_context_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", + mask); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void ase_decode_preferred_context(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + print_context(&frame, " Preferred Context"); +} + +static void ase_decode_context(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + print_context(&frame, " Context"); +} + +static void ase_decode_program_info(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + const char *str; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + str = l2cap_frame_pull(&frame, &frame, len); + if (!str) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Program Info: %s", str); + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +static void ase_decode_language(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + uint32_t value; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + if (!l2cap_frame_get_le24(&frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Language: 0x%6.6x", value); + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +struct packet_ltv_decoder ase_metadata_table[] = { + LTV_DEC(0x01, ase_decode_preferred_context), + LTV_DEC(0x02, ase_decode_context), + LTV_DEC(0x03, ase_decode_program_info), + LTV_DEC(0x04, ase_decode_language) +}; + static bool print_ase_metadata(const struct l2cap_frame *frame) { - return print_ase_lv(frame, " Metadata"); + return print_ase_lv(frame, " Metadata", NULL, 0); } +static const struct bitfield_data pac_freq_table[] = { + { 0, "8 Khz (0x0001)" }, + { 1, "11.25 Khz (0x0002)" }, + { 2, "16 Khz (0x0004)" }, + { 3, "22.05 Khz (0x0008)" }, + { 4, "24 Khz (0x0010)" }, + { 5, "32 Khz (0x0020)" }, + { 6, "44.1 Khz (0x0040)" }, + { 7, "48 Khz (0x0080)" }, + { 8, "88.2 Khz (0x0100)" }, + { 9, "96 Khz (0x0200)" }, + { 10, "176.4 Khz (0x0400)" }, + { 11, "192 Khz (0x0800)" }, + { 12, "384 Khz (0x1000)" }, + { 13, "RFU (0x2000)" }, + { 14, "RFU (0x4000)" }, + { 15, "RFU (0x8000)" }, + { } +}; + +static void pac_decode_freq(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + uint16_t value; + uint16_t mask; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + if (!l2cap_frame_get_le16(&frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Sampling Frequencies: 0x%4.4x", value); + + mask = print_bitfield(8, value, pac_freq_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", + mask); + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +static const struct bitfield_data pac_duration_table[] = { + { 0, "7.5 ms (0x01)" }, + { 1, "10 ms (0x02)" }, + { 2, "RFU (0x04)" }, + { 3, "RFU (0x08)" }, + { 4, "7.5 ms preferred (0x10)" }, + { 5, "10 ms preferred (0x20)" }, + { 6, "RFU (0x40)" }, + { 7, "RFU (0x80)" }, + { } +}; + +static void pac_decode_duration(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + uint8_t value; + uint8_t mask; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + if (!l2cap_frame_get_u8(&frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Frame Duration: 0x%4.4x", value); + + mask = print_bitfield(8, value, pac_duration_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)", + mask); + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +static const struct bitfield_data pac_channel_table[] = { + { 0, "1 channel (0x01)" }, + { 1, "2 channels (0x02)" }, + { 2, "3 channels (0x04)" }, + { 3, "4 chanenls (0x08)" }, + { 4, "5 channels (0x10)" }, + { 5, "6 channels (0x20)" }, + { 6, "7 channels (0x40)" }, + { 7, "8 channels (0x80)" }, + { } +}; + +static void pac_decode_channels(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + uint8_t value; + uint8_t mask; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + if (!l2cap_frame_get_u8(&frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Audio Channel Count: 0x%2.2x", value); + + mask = print_bitfield(8, value, pac_channel_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)", + mask); + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +static void pac_decode_frame_length(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + uint16_t min, max; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + if (!l2cap_frame_get_le16(&frame, &min)) { + print_text(COLOR_ERROR, " min: invalid size"); + goto done; + } + + if (!l2cap_frame_get_le16(&frame, &max)) { + print_text(COLOR_ERROR, " min: invalid size"); + goto done; + } + + print_field(" Frame Length: %u (0x%4.4x) - %u (0x%4.4x)", + min, min, max, max); + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +static void pac_decode_sdu(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + uint8_t value; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + if (!l2cap_frame_get_u8(&frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Max SDU: %u (0x%2.2x)", value, value); + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +struct packet_ltv_decoder pac_cap_table[] = { + LTV_DEC(0x01, pac_decode_freq), + LTV_DEC(0x02, pac_decode_duration), + LTV_DEC(0x03, pac_decode_channels), + LTV_DEC(0x04, pac_decode_frame_length), + LTV_DEC(0x05, pac_decode_sdu) +}; + static void print_pac(const struct l2cap_frame *frame) { uint8_t num = 0, i; @@ -326,7 +605,8 @@ static void print_pac(const struct l2cap_frame *frame) if (!print_ase_codec(frame)) goto done; - if (!print_ase_cc(frame)) + if (!print_ase_cc(frame, " Codec Specific Capabilities", + pac_cap_table, ARRAY_SIZE(pac_cap_table))) break; if (!print_ase_metadata(frame)) @@ -441,6 +721,210 @@ static bool print_ase_pd(const struct l2cap_frame *frame, const char *label) return true; } +static void ase_decode_freq(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + uint8_t value; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + if (!l2cap_frame_get_u8(&frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + switch (value) { + case 0x01: + print_field(" Sampling Frequency: 8 Khz (0x01)"); + break; + case 0x02: + print_field(" Sampling Frequency: 11.25 Khz (0x02)"); + break; + case 0x03: + print_field(" Sampling Frequency: 16 Khz (0x03)"); + break; + case 0x04: + print_field(" Sampling Frequency: 22.05 Khz (0x04)"); + break; + case 0x05: + print_field(" Sampling Frequency: 24 Khz (0x04)"); + break; + case 0x06: + print_field(" Sampling Frequency: 32 Khz (0x04)"); + break; + case 0x07: + print_field(" Sampling Frequency: 44.1 Khz (0x04)"); + break; + case 0x08: + print_field(" Sampling Frequency: 48 Khz (0x04)"); + break; + case 0x09: + print_field(" Sampling Frequency: 88.2 Khz (0x04)"); + break; + case 0x0a: + print_field(" Sampling Frequency: 96 Khz (0x04)"); + break; + case 0x0b: + print_field(" Sampling Frequency: 176.4 Khz (0x04)"); + break; + case 0x0c: + print_field(" Sampling Frequency: 192 Khz (0x04)"); + break; + case 0x0d: + print_field(" Sampling Frequency: 384 Khz (0x04)"); + break; + default: + print_field(" Sampling Frequency: RFU (0x%2.2x)", value); + break; + } + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +static void ase_decode_duration(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + uint8_t value; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + if (!l2cap_frame_get_u8(&frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + switch (value) { + case 0x00: + print_field(" Frame Duration: 7.5 ms (0x00)"); + break; + case 0x01: + print_field(" Frame Duration: 10 ms (0x01)"); + break; + default: + print_field(" Frame Duration: RFU (0x%2.2x)", value); + break; + } + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +static const struct bitfield_data channel_location_table[] = { + { 0, "Front Left (0x00000001)" }, + { 1, "Front Right (0x00000002)" }, + { 2, "Front Center (0x00000004)" }, + { 3, "Low Frequency Effects 1 (0x00000008)" }, + { 4, "Back Left (0x00000010)" }, + { 5, "Back Right (0x00000020)" }, + { 6, "Front Left of Center (0x00000040)" }, + { 7, "Front Right of Center (0x00000080)" }, + { 8, "Back Center (0x00000100)" }, + { 9, "Low Frequency Effects 2 (0x00000200)" }, + { 10, "Side Left (0x00000400)" }, + { 11, "Side Right (0x00000800)" }, + { 12, "Top Front Left (0x00001000)" }, + { 13, "Top Front Right (0x00002000)" }, + { 14, "Top Front Center (0x00004000)" }, + { 15, "Top Center (0x00008000)" }, + { 16, "Top Back Left (0x00010000)" }, + { 17, "Top Back Right (0x00020000)" }, + { 18, "Top Side Left (0x00040000)" }, + { 19, "Top Side Right (0x00080000)" }, + { 20, "Top Back Center (0x00100000)" }, + { 21, "Bottom Front Center (0x00200000)" }, + { 22, "Bottom Front Left (0x00400000)" }, + { 23, "Bottom Front Right (0x00800000)" }, + { 24, "Front Left Wide (0x01000000)" }, + { 25, "Front Right Wide (0x02000000)" }, + { 26, "Left Surround (0x04000000)" }, + { 27, "Right Surround (0x08000000)" }, + { 28, "RFU (0x10000000)" }, + { 29, "RFU (0x20000000)" }, + { 30, "RFU (0x40000000)" }, + { 31, "RFU (0x80000000)" }, + { } +}; + +static void print_location(const struct l2cap_frame *frame) +{ + uint32_t value; + uint32_t mask; + + if (!l2cap_frame_get_le32((void *)frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Location: 0x%8.8x", value); + + mask = print_bitfield(6, value, channel_location_table); + if (mask) + print_text(COLOR_WHITE_BG, " Unknown fields (0x%8.8x)", + mask); + +done: + if (frame->size) + print_hex_field(" Data", frame->data, frame->size); +} + +static void ase_decode_location(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + print_location(&frame); +} + +static void ase_decode_frame_length(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + uint16_t value; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + if (!l2cap_frame_get_le16(&frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Frame Length: %u (0x%4.4x)", value, value); + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +static void ase_decode_blocks(const uint8_t *data, uint8_t len) +{ + struct l2cap_frame frame; + uint8_t value; + + l2cap_frame_init(&frame, 0, 0, 0, 0, 0, 0, data, len); + + if (!l2cap_frame_get_u8(&frame, &value)) { + print_text(COLOR_ERROR, " value: invalid size"); + goto done; + } + + print_field(" Frame Blocks per SDU: %u (0x%2.2x)", value, value); + +done: + if (frame.size) + print_hex_field(" Data", frame.data, frame.size); +} + +struct packet_ltv_decoder ase_cc_table[] = { + LTV_DEC(0x01, ase_decode_freq), + LTV_DEC(0x02, ase_decode_duration), + LTV_DEC(0x03, ase_decode_location), + LTV_DEC(0x04, ase_decode_frame_length), + LTV_DEC(0x05, ase_decode_blocks) +}; + static void print_ase_config(const struct l2cap_frame *frame) { if (!print_prefer_framing(frame)) @@ -470,7 +954,8 @@ static void print_ase_config(const struct l2cap_frame *frame) if (!print_ase_codec(frame)) return; - print_ase_cc(frame); + print_ase_cc(frame, " Codec Specific Configuration", + ase_cc_table, ARRAY_SIZE(ase_cc_table)); } static bool print_ase_framing(const struct l2cap_frame *frame, @@ -704,7 +1189,8 @@ static bool ase_config_cmd(const struct l2cap_frame *frame) if (!print_ase_codec(frame)) return false; - if (!print_ase_cc(frame)) + if (!print_ase_cc(frame, " Codec Specific Configuration", + ase_cc_table, ARRAY_SIZE(ase_cc_table))) return false; return true; @@ -1050,100 +1536,23 @@ static void ase_cp_notify(const struct l2cap_frame *frame) print_ase_cp_rsp(frame); } -static const struct bitfield_data pac_loc_table[] = { - { 0, "Front Left (0x00000001)" }, - { 1, "Front Right (0x00000002)" }, - { 2, "Front Center (0x00000004)" }, - { 3, "Low Frequency Effects 1 (0x00000008)" }, - { 4, "Back Left (0x00000010)" }, - { 5, "Back Right (0x00000020)" }, - { 6, "Front Left of Center (0x00000040)" }, - { 7, "Front Right of Center (0x00000080)" }, - { 8, "Back Center (0x00000100)" }, - { 9, "Low Frequency Effects 2 (0x00000200)" }, - { 10, "Side Left (0x00000400)" }, - { 11, "Side Right (0x00000800)" }, - { 12, "Top Front Left (0x00001000)" }, - { 13, "Top Front Right (0x00002000)" }, - { 14, "Top Front Center (0x00004000)" }, - { 15, "Top Center (0x00008000)" }, - { 16, "Top Back Left (0x00010000)" }, - { 17, "Top Back Right (0x00020000)" }, - { 18, "Top Side Left (0x00040000)" }, - { 19, "Top Side Right (0x00080000)" }, - { 20, "Top Back Center (0x00100000)" }, - { 21, "Bottom Front Center (0x00200000)" }, - { 22, "Bottom Front Left (0x00400000)" }, - { 23, "Bottom Front Right (0x00800000)" }, - { 24, "Front Left Wide (0x01000000)" }, - { 25, "Front Right Wide (0x02000000)" }, - { 26, "Left Surround (0x04000000)" }, - { 27, "Right Surround (0x08000000)" }, - { 28, "RFU (0x10000000)" }, - { 29, "RFU (0x20000000)" }, - { 30, "RFU (0x40000000)" }, - { 31, "RFU (0x80000000)" }, - { } -}; - -static void print_loc_pac(const struct l2cap_frame *frame) -{ - uint32_t value; - uint8_t mask; - - if (!l2cap_frame_get_le32((void *)frame, &value)) { - print_text(COLOR_ERROR, " value: invalid size"); - goto done; - } - - print_field(" Location: 0x%8.8x", value); - - mask = print_bitfield(4, value, pac_loc_table); - if (mask) - print_text(COLOR_WHITE_BG, " Unknown fields (0x%2.2x)", - mask); - -done: - if (frame->size) - print_hex_field(" Data", frame->data, frame->size); -} - static void pac_loc_read(const struct l2cap_frame *frame) { - print_loc_pac(frame); + print_location(frame); } static void pac_loc_notify(const struct l2cap_frame *frame) { - print_loc_pac(frame); + print_location(frame); } -static const struct bitfield_data pac_context_table[] = { - { 0, "Unspecified (0x0001)" }, - { 1, "Conversational (0x0002)" }, - { 2, "Media (0x0004)" }, - { 3, "Game (0x0008)" }, - { 4, "Instructional (0x0010)" }, - { 5, "Voice Assistants (0x0020)" }, - { 6, "Live (0x0040)" }, - { 7, "Sound Effects (0x0080)" }, - { 8, "Notifications (0x0100)" }, - { 9, "Ringtone (0x0200)" }, - { 10, "Alerts (0x0400)" }, - { 11, "Emergency alarm (0x0800)" }, - { 12, "RFU (0x1000)" }, - { 13, "RFU (0x2000)" }, - { 14, "RFU (0x4000)" }, - { 15, "RFU (0x8000)" }, -}; - static void print_pac_context(const struct l2cap_frame *frame) { uint16_t snk, src; uint16_t mask; if (!l2cap_frame_get_le16((void *)frame, &snk)) { - print_text(COLOR_ERROR, " value: invalid size"); + print_text(COLOR_ERROR, " sink: invalid size"); goto done; } @@ -1151,11 +1560,11 @@ static void print_pac_context(const struct l2cap_frame *frame) mask = print_bitfield(4, snk, pac_context_table); if (mask) - print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", + print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", mask); if (!l2cap_frame_get_le16((void *)frame, &src)) { - print_text(COLOR_ERROR, " sink: invalid size"); + print_text(COLOR_ERROR, " source: invalid size"); goto done; } @@ -1163,7 +1572,7 @@ static void print_pac_context(const struct l2cap_frame *frame) mask = print_bitfield(4, src, pac_context_table); if (mask) - print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", + print_text(COLOR_WHITE_BG, " Unknown fields (0x%4.4x)", mask); done: diff --git a/monitor/packet.c b/monitor/packet.c index bd9efd2c7..3efa5a25d 100644 --- a/monitor/packet.c +++ b/monitor/packet.c @@ -3338,7 +3338,26 @@ static void *iov_pull(struct iovec *iov, size_t len) return data; } -static void print_ltv(const char *label, const uint8_t *data, uint8_t len) +static struct packet_ltv_decoder* +get_ltv_decoder(struct packet_ltv_decoder *decoder, size_t num, uint8_t type) +{ + size_t i; + + if (!decoder || !num) + return NULL; + + for (i = 0; i < num; i++) { + struct packet_ltv_decoder *dec = &decoder[i]; + + if (dec->type == type) + return dec; + } + + return NULL; +} + +static void print_ltv(const char *label, const uint8_t *data, uint8_t len, + struct packet_ltv_decoder *decoder, size_t num) { struct iovec iov; int i; @@ -3348,6 +3367,7 @@ static void print_ltv(const char *label, const uint8_t *data, uint8_t len) for (i = 0; iov.iov_len; i++) { uint8_t l, t, *v; + struct packet_ltv_decoder *dec; l = get_u8(iov_pull(&iov, sizeof(l))); if (!l) { @@ -3369,16 +3389,21 @@ static void print_ltv(const char *label, const uint8_t *data, uint8_t len) if (!v) break; - print_hex_field(label, v, l); + dec = get_ltv_decoder(decoder, num, t); + if (dec) + dec->func(v, l); + else + print_hex_field(label, v, l); } if (iov.iov_len) print_hex_field(label, iov.iov_base, iov.iov_len); } -void packet_print_ltv(const char *label, const uint8_t *data, uint8_t len) +void packet_print_ltv(const char *label, const uint8_t *data, uint8_t len, + struct packet_ltv_decoder *decoder, size_t decoder_len) { - print_ltv(label, data, len); + print_ltv(label, data, len, decoder, decoder_len); } static void print_base_annoucement(const uint8_t *data, uint8_t data_len) @@ -3432,7 +3457,8 @@ static void print_base_annoucement(const uint8_t *data, uint8_t data_len) goto done; print_ltv(" Codec Specific Configuration", - codec_cfg->data, codec_cfg->len); + codec_cfg->data, codec_cfg->len, + NULL, 0); metadata = iov_pull(&iov, sizeof(*metadata)); if (!metadata) @@ -3441,7 +3467,8 @@ static void print_base_annoucement(const uint8_t *data, uint8_t data_len) if (!iov_pull(&iov, metadata->len)) goto done; - print_ltv(" Metadata", metadata->data, metadata->len); + print_ltv(" Metadata", metadata->data, metadata->len, + NULL, 0); /* Level 3 - BIS(s)*/ for (j = 0; j < subgroup->num_bis; j++) { diff --git a/monitor/packet.h b/monitor/packet.h index 3a6b9f7a1..b07d5d18c 100644 --- a/monitor/packet.h +++ b/monitor/packet.h @@ -63,7 +63,20 @@ void packet_print_channel_map_ll(const uint8_t *map); void packet_print_io_capability(uint8_t capability); void packet_print_io_authentication(uint8_t authentication); void packet_print_codec_id(const char *label, uint8_t codec); -void packet_print_ltv(const char *label, const uint8_t *data, uint8_t len); + +#define LTV_DEC(_type, _func) \ +{ \ + .type = _type, \ + .func = _func, \ +} + +struct packet_ltv_decoder { + uint8_t type; + void (*func)(const uint8_t *data, uint8_t len); +}; + +void packet_print_ltv(const char *label, const uint8_t *data, uint8_t len, + struct packet_ltv_decoder *decoder, size_t num); void packet_control(struct timeval *tv, struct ucred *cred, uint16_t index, uint16_t opcode,