From patchwork Fri Feb 28 23:46:50 2020 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: 197333 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B1FDDC3F2D2 for ; Fri, 28 Feb 2020 23:47:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 78C6A246B7 for ; Fri, 28 Feb 2020 23:47:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="JAE41cfz" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726589AbgB1XrG (ORCPT ); Fri, 28 Feb 2020 18:47:06 -0500 Received: from mail-pj1-f45.google.com ([209.85.216.45]:33922 "EHLO mail-pj1-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726525AbgB1XrF (ORCPT ); Fri, 28 Feb 2020 18:47:05 -0500 Received: by mail-pj1-f45.google.com with SMTP id f2so4702733pjq.1 for ; Fri, 28 Feb 2020 15:47:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=a4mt3tuBEtrcFQaO04FkgRzkU5NWsbNKqrXQXndd3Lo=; b=JAE41cfzDEddUoF89z01cmKJCa1ICMR9riB04GVa9TLtSknXNHkpIhyyppzRG53vzz oDDlUJSbi00CAGUrQYi6DafximPtDrQ1fWeMxJK8vCs4CY8jk8qHkt8J4XWnaJOUu251 8GtmkHypZ1exTEl3lYL9KVrymahP1MJI2ePCtuIXsOAcxZfeBB2wgNUPk+wAqRb9uztF BHwqk6++kEmceWxEyDaGrxTF2kFefVKSExvVLIf0RK63Qd7QRLDc7xClGDrmaUCWw9aq 3kam9VAO5+FAoO5VjIiEAhLyXuyaBSbg6Tjt8T4jIg9hl5yPoYew9qdMFDduvaaq1zx0 WNSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=a4mt3tuBEtrcFQaO04FkgRzkU5NWsbNKqrXQXndd3Lo=; b=HbGTZ4yrGL0yPwPbwcBfuZfiDz0++fZeHgM2k1y55RYmj6cmfS0cxITModReyGvh5j JAFQ9dVNCFKF82N7BRKtYQbVrfesRVwIDBod7Ymoa0vQajO+3NxV8XpyPc7Ca4qJoSw9 mK4msGW74E/AIfqCC2MOjibRspowaFcCv+IyMLPASxNdw/6pf6neIW/3IF2ijNJrTVhA aCam9+Bi+kp9MapQEEkHScS5YbZ9Wc5Ya/wD4BohEyy6S1OJHe/5GznQkYTWDZqPlk6U 2FGn0q8SlnJyW1VKeR+VTwwaHPG67shQE4wlZontk5siw6ZaKSv1x8b6DPSnX2eEghcA c4SA== X-Gm-Message-State: APjAAAVOH2dOk50cmmjkjoWIcB7GkGyyWRjxT1jxxWap9ou8jqctC9Pk GY5FIXX+cwrMTg2hFome8ppxVUaRAkk= X-Google-Smtp-Source: APXvYqwblYvciv7f7kHmDiW0jcNlt2mK1qRYN2plv6ZAr9Rs3xy9LrI88P8X2YIIRAdtYLuJZPMc4Q== X-Received: by 2002:a17:90a:17e5:: with SMTP id q92mr7484160pja.28.1582933624183; Fri, 28 Feb 2020 15:47:04 -0800 (PST) Received: from localhost.localdomain (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id q13sm13643954pfn.162.2020.02.28.15.47.03 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2020 15:47:03 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH v2 01/12] lib: Add definitions for Enhanced Credits Based Mode Date: Fri, 28 Feb 2020 15:46:50 -0800 Message-Id: <20200228234701.14614-2-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200228234701.14614-1-luiz.dentz@gmail.com> References: <20200228234701.14614-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz --- lib/bluetooth.h | 2 ++ lib/l2cap.h | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/bluetooth.h b/lib/bluetooth.h index d14217eac..47521d50e 100644 --- a/lib/bluetooth.h +++ b/lib/bluetooth.h @@ -141,6 +141,8 @@ struct bt_voice { #define BT_PHY_LE_CODED_TX 0x00002000 #define BT_PHY_LE_CODED_RX 0x00004000 +#define BT_MODE 15 + /* Connection and socket states */ enum { BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */ diff --git a/lib/l2cap.h b/lib/l2cap.h index 5ce94c4ee..f9ceb2f33 100644 --- a/lib/l2cap.h +++ b/lib/l2cap.h @@ -197,6 +197,7 @@ typedef struct { #define L2CAP_MODE_FLOWCTL 0x02 #define L2CAP_MODE_ERTM 0x03 #define L2CAP_MODE_STREAMING 0x04 +#define L2CAP_MODE_EXT_FLOWCTL 0x81 #define L2CAP_SERVTYPE_NOTRAFFIC 0x00 #define L2CAP_SERVTYPE_BESTEFFORT 0x01 From patchwork Fri Feb 28 23:46:51 2020 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: 197332 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 821A8C3F2D4 for ; Fri, 28 Feb 2020 23:47:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 580BC246B5 for ; Fri, 28 Feb 2020 23:47:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CVarktRL" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726658AbgB1XrH (ORCPT ); Fri, 28 Feb 2020 18:47:07 -0500 Received: from mail-pl1-f172.google.com ([209.85.214.172]:44861 "EHLO mail-pl1-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726621AbgB1XrG (ORCPT ); Fri, 28 Feb 2020 18:47:06 -0500 Received: by mail-pl1-f172.google.com with SMTP id d9so1827783plo.11 for ; Fri, 28 Feb 2020 15:47:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=XGWE9lkXskeRh9mJU7EOBpH5ngFpikJQY3KMiOnIcZA=; b=CVarktRLphIVsaupESJaDJPI+GeH5pN9S1eJJtuTaUIwhvvdjuPBOnshRQkp8Wt79B 3GRDcnAeq4E2wn2duzDr482x9iwR37Ak0oaDuOa8WxQ8in+8QqLcSlBsLQqPRIUtzfJ/ 8NYQB9luotpofWUyZUfN1Um/A34Ba0zC1b7cwlKmzzj2amf1hcO1ug/OnEdsjmur9f/5 d8WgjtNnDMqu3uzu++Y/AfE6tXK/BdH59mbBnOBIhJJeFWDaSsevFlPxi4AvDy0UIWT7 ih+RsQjXzlZzyCUTpSITkypXIkHVdv/+R75POcwJ4/UHqFgNSXArZlYv0CMfylc14FoS ViEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=XGWE9lkXskeRh9mJU7EOBpH5ngFpikJQY3KMiOnIcZA=; b=Co+AKcbDL/GhPGlgfrxQ2mTHthILgIO9Rahm1qlgvfsoQOpQ5Cx/RtCjbhwL6WQHtk uQwyAy0EUn0MAwpYDYbVgqbuRDDmVaNpjuK5lLvkNS1BSf6k94RyvQe18wfuywT8wnGU 5dzgNlbTmpiKTRldxN5QmNg4lUB7E/RcY2QEQ3Oi9HGFcZVSXeCJkYh8rmDHsmJa+646 gawLa9YTtXvkFLFHqTuMJUqNDrworCPABzdOuMi/+jQFTAVatrIefZBFXfagDbBWuCAz m2xoVRXx1wNzSCbeHvhr2bEKh52p6XuLzjRE1vT1y8AwBSYk/5gAW5qD7tJUG9WdXfwj mr/w== X-Gm-Message-State: APjAAAWv8Bc4XVIWpy0kbvtlUpgFodWsUKrcHTJ6WHKZUi8LZC438IfC GnNaUdbOnwFFKOsdHrr0HOe6CbAEge0= X-Google-Smtp-Source: APXvYqzxouOEocRjtAd84wyirrhsFWVMy42AjkdaOacpoeWN117HE9Az+aByaDJvxb/M/J7bDOJD/g== X-Received: by 2002:a17:902:c113:: with SMTP id 19mr6390408pli.138.1582933625315; Fri, 28 Feb 2020 15:47:05 -0800 (PST) Received: from localhost.localdomain (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id q13sm13643954pfn.162.2020.02.28.15.47.04 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2020 15:47:04 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH v2 02/12] btio: Add mode to for Enhanced Credit Mode Date: Fri, 28 Feb 2020 15:46:51 -0800 Message-Id: <20200228234701.14614-3-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200228234701.14614-1-luiz.dentz@gmail.com> References: <20200228234701.14614-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz This adds BT_IO_MODE_ECRED which directly maps to L2CAP_MODE_ECRED. --- btio/btio.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++------ btio/btio.h | 3 ++- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/btio/btio.c b/btio/btio.c index db37b99da..4c84da0ee 100644 --- a/btio/btio.c +++ b/btio/btio.c @@ -630,18 +630,34 @@ static gboolean set_le_imtu(int sock, uint16_t imtu, GError **err) return TRUE; } +static gboolean set_le_mode(int sock, uint8_t mode, GError **err) +{ + if (setsockopt(sock, SOL_BLUETOOTH, BT_MODE, &mode, + sizeof(mode)) < 0) { + ERROR_FAILED(err, "setsockopt(BT_MODE)", errno); + return FALSE; + } + + return TRUE; +} + static gboolean l2cap_set(int sock, uint8_t src_type, int sec_level, uint16_t imtu, uint16_t omtu, uint8_t mode, int master, int flushable, uint32_t priority, GError **err) { if (imtu || omtu || mode) { - gboolean ret; + gboolean ret = FALSE; if (src_type == BDADDR_BREDR) ret = set_l2opts(sock, imtu, omtu, mode, err); - else - ret = set_le_imtu(sock, imtu, err); + else { + if (imtu) + ret = set_le_imtu(sock, imtu, err); + + if (ret && mode) + ret = set_le_mode(sock, mode, err); + } if (!ret) return ret; @@ -980,6 +996,30 @@ static int get_phy(int sock, uint32_t *phy) return 0; } +static int get_le_imtu(int sock, uint16_t *mtu) +{ + socklen_t len; + + len = sizeof(*mtu); + + if (getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, mtu, &len) < 0) + return -errno; + + return 0; +} + +static int get_le_mode(int sock, uint8_t *mode) +{ + socklen_t len; + + len = sizeof(*mode); + + if (getsockopt(sock, SOL_BLUETOOTH, BT_MODE, mode, &len) < 0) + return -errno; + + return 0; +} + static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1, va_list args) { @@ -999,10 +1039,11 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1, memset(&l2o, 0, sizeof(l2o)); if (src.l2_bdaddr_type != BDADDR_BREDR) { - len = sizeof(l2o.imtu); - if (getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, - &l2o.imtu, &len) == 0) + if (get_le_imtu(sock, &l2o.imtu) == 0) { + /* Older kernels may not support BT_MODE */ + get_le_mode(sock, &l2o.mode); goto parse_opts; + } /* Non-LE CoC enabled kernels will return one of these * in which case we need to fall back to L2CAP_OPTIONS. diff --git a/btio/btio.h b/btio/btio.h index 41a017acb..5ebfb85c6 100644 --- a/btio/btio.h +++ b/btio/btio.h @@ -71,7 +71,8 @@ typedef enum { BT_IO_MODE_RETRANS, BT_IO_MODE_FLOWCTL, BT_IO_MODE_ERTM, - BT_IO_MODE_STREAMING + BT_IO_MODE_STREAMING, + BT_IO_MODE_EXT_FLOWCTL = 0x81 } BtIOMode; typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data); From patchwork Fri Feb 28 23:46:53 2020 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: 197331 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6B360C3F2D2 for ; Fri, 28 Feb 2020 23:47:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 09B01246B5 for ; Fri, 28 Feb 2020 23:47:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="juUoUVo+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726695AbgB1XrK (ORCPT ); Fri, 28 Feb 2020 18:47:10 -0500 Received: from mail-pf1-f195.google.com ([209.85.210.195]:37931 "EHLO mail-pf1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725957AbgB1XrK (ORCPT ); Fri, 28 Feb 2020 18:47:10 -0500 Received: by mail-pf1-f195.google.com with SMTP id x185so2499100pfc.5 for ; Fri, 28 Feb 2020 15:47:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=P7v08WPCJmgOE+zN+pZI071+aDIMN916uP0KQpxtxkc=; b=juUoUVo+l9t1SMSbRzM6G/q3idaKgZFJ0Ubfj+QxqGwT1Co/62YGVThvZyNnnYYcyb s9djdwHuxuioji4Ju8BFckrDIurLFrsgpg3qtwy22B1DW2/YBBxU7/2sCiKEzpqUSWOP pncJIsodxz3c0x70sXc91X5JBH7TfvW8h6FAShQgBkKIn+ojYomVxl0XHhXtZvumoIUj RYyv4w6trQLOMb3OpI18gCzE7o8KRNeVBRfI7azdWNaJowssdJgVuTA8DZR6P2bE0YwL kTxiLDB9LUF+Em4QVbBhQcKWU/7PER5rhCvpoIIyNFOnS2q9RyxO57OigDKj9iSEkZ8h 9UZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=P7v08WPCJmgOE+zN+pZI071+aDIMN916uP0KQpxtxkc=; b=hOP14/hF3LIiPJpAjDQZ+95q9QMVzHh3/GDWtDaM9OCFjdw/YYKmSCLMlTzKhP+QvT jaHUmnQfK9ql/kjEcXj2GYb137pBsArArIUHxFjqHXI/YbqMWrYxcs6wdCYyJTkin8is SdDfx51jYZL8i26Ldw+cZH1e5svmTB1lwh11zvzUGnMUApbgIIUwahFzsfbRBJ7SeSyy mKpsZgI09tZuiEkBgR7DFIuqGxzUP2R85Dd9N8oqd1vPoIFs7IqcNnPpS1jVDxioeR3P af+oDkZF2tSWkHyA3xy0XgguAGy1UIC/QfIYElQoEVhp7R8IaJms2jvBdoB1c3iuM/Ha jnog== X-Gm-Message-State: APjAAAX531REcS34xKbkDDow+SjJgl04gxast2GZxFa5FsVWMQ7crM7W I1KJRwMpR8lpi6BUs0eR/engV9KFM+A= X-Google-Smtp-Source: APXvYqwgbDlOWZX8XcbO5NU1uTistB/cMXNdOoVtHipYJgkMuEirzo26t82MGWUIto78tnCV9CkJSw== X-Received: by 2002:a62:768d:: with SMTP id r135mr6463474pfc.108.1582933627648; Fri, 28 Feb 2020 15:47:07 -0800 (PST) Received: from localhost.localdomain (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id q13sm13643954pfn.162.2020.02.28.15.47.06 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2020 15:47:06 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH v2 04/12] share/att: Add EATT support Date: Fri, 28 Feb 2020 15:46:53 -0800 Message-Id: <20200228234701.14614-5-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200228234701.14614-1-luiz.dentz@gmail.com> References: <20200228234701.14614-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz This adds EATT support to bt_att, EATT bearers are handled as additional channels which auto allocated for queued requests. --- src/gatt-database.c | 4 +- src/shared/att-types.h | 16 +- src/shared/att.c | 566 +++++++++++++++++++++++++-------------- src/shared/att.h | 4 + src/shared/gatt-client.c | 2 +- 5 files changed, 389 insertions(+), 203 deletions(-) diff --git a/src/gatt-database.c b/src/gatt-database.c index 2bae8711a..419e4f9e1 100644 --- a/src/gatt-database.c +++ b/src/gatt-database.c @@ -2102,10 +2102,10 @@ static void append_options(DBusMessageIter *iter, void *user_data) uint16_t mtu; switch (op->link_type) { - case BT_ATT_LINK_BREDR: + case BT_ATT_BREDR: link = "BR/EDR"; break; - case BT_ATT_LINK_LE: + case BT_ATT_LE: link = "LE"; break; default: diff --git a/src/shared/att-types.h b/src/shared/att-types.h index 8a2658de3..7b88e7d92 100644 --- a/src/shared/att-types.h +++ b/src/shared/att-types.h @@ -27,6 +27,10 @@ #define __packed __attribute__((packed)) #endif +#define BT_ATT_CID 4 +#define BT_ATT_PSM 31 +#define BT_ATT_EATT_PSM 0x27 + #define BT_ATT_SECURITY_AUTO 0 #define BT_ATT_SECURITY_LOW 1 #define BT_ATT_SECURITY_MEDIUM 2 @@ -37,9 +41,10 @@ #define BT_ATT_MAX_LE_MTU 517 #define BT_ATT_MAX_VALUE_LEN 512 -#define BT_ATT_LINK_BREDR 0x00 -#define BT_ATT_LINK_LE 0x01 -#define BT_ATT_LINK_LOCAL 0xff +#define BT_ATT_BREDR 0x00 +#define BT_ATT_LE 0x01 +#define BT_ATT_EATT 0x02 +#define BT_ATT_LOCAL 0xff /* ATT protocol opcodes */ #define BT_ATT_OP_ERROR_RSP 0x01 @@ -159,3 +164,8 @@ struct bt_att_pdu_error_rsp { /* GATT Characteristic Client Features Bitfield values */ #define BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING 0x01 +#define BT_GATT_CHRC_CLI_FEAT_EATT 0x02 +#define BT_GATT_CHRC_CLI_FEAT_NFY_MULTI 0x04 + +/* GATT Characteristic Server Features Bitfield values */ +#define BT_GATT_CHRC_SERVER_FEAT_EATT 0x01 diff --git a/src/shared/att.c b/src/shared/att.c index 0ea6d55bd..1313703f9 100644 --- a/src/shared/att.c +++ b/src/shared/att.c @@ -49,32 +49,40 @@ struct att_send_op; -struct bt_att { - int ref_count; +struct bt_att_chan { + struct bt_att *att; int fd; struct io *io; - bool io_on_l2cap; - int io_sec_level; /* Only used for non-L2CAP */ - uint8_t enc_size; + uint8_t type; + int sec_level; /* Only used for non-L2CAP */ - struct queue *req_queue; /* Queued ATT protocol requests */ struct att_send_op *pending_req; - struct queue *ind_queue; /* Queued ATT protocol indications */ struct att_send_op *pending_ind; - struct queue *write_queue; /* Queue of PDUs ready to send */ bool writer_active; - struct queue *notify_list; /* List of registered callbacks */ - struct queue *disconn_list; /* List of disconnect handlers */ - bool in_req; /* There's a pending incoming request */ uint8_t *buf; uint16_t mtu; +}; + +struct bt_att { + int ref_count; + bool close_on_unref; + struct queue *chans; + uint8_t enc_size; + uint16_t mtu; /* Biggest possible MTU */ + + struct queue *notify_list; /* List of registered callbacks */ + struct queue *disconn_list; /* List of disconnect handlers */ unsigned int next_send_id; /* IDs for "send" ops */ unsigned int next_reg_id; /* IDs for registered callbacks */ + struct queue *req_queue; /* Queued ATT protocol requests */ + struct queue *ind_queue; /* Queued ATT protocol indications */ + struct queue *write_queue; /* Queue of PDUs ready to send */ + bt_att_timeout_func_t timeout_callback; bt_att_destroy_func_t timeout_destroy; void *timeout_data; @@ -362,8 +370,9 @@ static struct att_send_op *create_att_send_op(struct bt_att *att, return op; } -static struct att_send_op *pick_next_send_op(struct bt_att *att) +static struct att_send_op *pick_next_send_op(struct bt_att_chan *chan) { + struct bt_att *att = chan->att; struct att_send_op *op; /* See if any operations are already in the write queue */ @@ -374,7 +383,7 @@ static struct att_send_op *pick_next_send_op(struct bt_att *att) /* If there is no pending request, pick an operation from the * request queue. */ - if (!att->pending_req) { + if (!chan->pending_req) { op = queue_pop_head(att->req_queue); if (op) return op; @@ -383,7 +392,7 @@ static struct att_send_op *pick_next_send_op(struct bt_att *att) /* There is either a request pending or no requests queued. If there is * no pending indication, pick an operation from the indication queue. */ - if (!att->pending_ind) { + if (!chan->pending_ind) { op = queue_pop_head(att->ind_queue); if (op) return op; @@ -393,22 +402,23 @@ static struct att_send_op *pick_next_send_op(struct bt_att *att) } struct timeout_data { - struct bt_att *att; + struct bt_att_chan *chan; unsigned int id; }; static bool timeout_cb(void *user_data) { struct timeout_data *timeout = user_data; - struct bt_att *att = timeout->att; + struct bt_att_chan *chan = timeout->chan; + struct bt_att *att = chan->att; struct att_send_op *op = NULL; - if (att->pending_req && att->pending_req->id == timeout->id) { - op = att->pending_req; - att->pending_req = NULL; - } else if (att->pending_ind && att->pending_ind->id == timeout->id) { - op = att->pending_ind; - att->pending_ind = NULL; + if (chan->pending_req && chan->pending_req->id == timeout->id) { + op = chan->pending_req; + chan->pending_req = NULL; + } else if (chan->pending_ind && chan->pending_ind->id == timeout->id) { + op = chan->pending_ind; + chan->pending_ind = NULL; } if (!op) @@ -428,27 +438,28 @@ static bool timeout_cb(void *user_data) * This should trigger an io disconnect event which will clean up the * io and notify the upper layer. */ - io_shutdown(att->io); + io_shutdown(chan->io); return false; } static void write_watch_destroy(void *user_data) { - struct bt_att *att = user_data; + struct bt_att_chan *chan = user_data; - att->writer_active = false; + chan->writer_active = false; } static bool can_write_data(struct io *io, void *user_data) { - struct bt_att *att = user_data; + struct bt_att_chan *chan = user_data; + struct bt_att *att = chan->att; struct att_send_op *op; struct timeout_data *timeout; ssize_t ret; struct iovec iov; - op = pick_next_send_op(att); + op = pick_next_send_op(chan); if (!op) return false; @@ -478,14 +489,14 @@ static bool can_write_data(struct io *io, void *user_data) */ switch (op->type) { case ATT_OP_TYPE_REQ: - att->pending_req = op; + chan->pending_req = op; break; case ATT_OP_TYPE_IND: - att->pending_ind = op; + chan->pending_ind = op; break; case ATT_OP_TYPE_RSP: /* Set in_req to false to indicate that no request is pending */ - att->in_req = false; + chan->in_req = false; /* fall through */ case ATT_OP_TYPE_CMD: case ATT_OP_TYPE_NOT: @@ -497,7 +508,7 @@ static bool can_write_data(struct io *io, void *user_data) } timeout = new0(struct timeout_data, 1); - timeout->att = att; + timeout->chan = chan; timeout->id = op->id; op->timeout_id = timeout_add(ATT_TIMEOUT_INTERVAL, timeout_cb, timeout, free); @@ -506,25 +517,33 @@ static bool can_write_data(struct io *io, void *user_data) return true; } -static void wakeup_writer(struct bt_att *att) +static void wakeup_chan_writer(void *data, void *user_data) { - if (att->writer_active) + struct bt_att_chan *chan = data; + struct bt_att *att = chan->att; + + if (chan->writer_active) return; /* Set the write handler only if there is anything that can be sent * at all. */ if (queue_isempty(att->write_queue)) { - if ((att->pending_req || queue_isempty(att->req_queue)) && - (att->pending_ind || queue_isempty(att->ind_queue))) + if ((chan->pending_req || queue_isempty(att->req_queue)) && + (chan->pending_ind || queue_isempty(att->ind_queue))) return; } - if (!io_set_write_handler(att->io, can_write_data, att, + if (!io_set_write_handler(chan->io, can_write_data, chan, write_watch_destroy)) return; - att->writer_active = true; + chan->writer_active = true; +} + +static void wakeup_writer(struct bt_att *att) +{ + queue_foreach(att->chans, wakeup_chan_writer, NULL); } static void disconn_handler(void *data, void *user_data) @@ -549,44 +568,66 @@ static void disc_att_send_op(void *data) destroy_att_send_op(op); } +static void bt_att_chan_free(void *data) +{ + struct bt_att_chan *chan = data; + + if (chan->pending_req) + destroy_att_send_op(chan->pending_req); + + if (chan->pending_ind) + destroy_att_send_op(chan->pending_ind); + + io_destroy(chan->io); + + free(chan->buf); + free(chan); +} + static bool disconnect_cb(struct io *io, void *user_data) { - struct bt_att *att = user_data; + struct bt_att_chan *chan = user_data; + struct bt_att *att = chan->att; int err; socklen_t len; len = sizeof(err); - if (getsockopt(att->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { - util_debug(att->debug_callback, att->debug_data, + if (getsockopt(chan->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { + util_debug(chan->att->debug_callback, chan->att->debug_data, "Failed to obtain disconnect error: %s", strerror(errno)); err = 0; } - util_debug(att->debug_callback, att->debug_data, - "Physical link disconnected: %s", - strerror(err)); + util_debug(chan->att->debug_callback, chan->att->debug_data, + "Channel %p disconnected: %s", + chan, strerror(err)); - io_destroy(att->io); - att->io = NULL; - att->fd = -1; + /* Dettach channel */ + queue_remove(att->chans, chan); /* Notify request callbacks */ queue_remove_all(att->req_queue, NULL, NULL, disc_att_send_op); queue_remove_all(att->ind_queue, NULL, NULL, disc_att_send_op); queue_remove_all(att->write_queue, NULL, NULL, disc_att_send_op); - if (att->pending_req) { - disc_att_send_op(att->pending_req); - att->pending_req = NULL; + if (chan->pending_req) { + disc_att_send_op(chan->pending_req); + chan->pending_req = NULL; } - if (att->pending_ind) { - disc_att_send_op(att->pending_ind); - att->pending_ind = NULL; + if (chan->pending_ind) { + disc_att_send_op(chan->pending_ind); + chan->pending_ind = NULL; } + bt_att_chan_free(chan); + + /* Don't run disconnect callback if there are channels left */ + if (!queue_isempty(att->chans)) + return false; + bt_att_ref(att); queue_foreach(att->disconn_list, disconn_handler, INT_TO_PTR(err)); @@ -597,14 +638,49 @@ static bool disconnect_cb(struct io *io, void *user_data) return false; } -static bool change_security(struct bt_att *att, uint8_t ecode) +static int bt_att_chan_get_security(struct bt_att_chan *chan) +{ + struct bt_security sec; + socklen_t len; + + if (chan->type == BT_ATT_LOCAL) + return chan->sec_level; + + memset(&sec, 0, sizeof(sec)); + len = sizeof(sec); + if (getsockopt(chan->fd, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) < 0) + return -EIO; + + return sec.level; +} + +static bool bt_att_chan_set_security(struct bt_att_chan *chan, int level) +{ + struct bt_security sec; + + if (chan->type == BT_ATT_LOCAL) { + chan->sec_level = level; + return true; + } + + memset(&sec, 0, sizeof(sec)); + sec.level = level; + + if (setsockopt(chan->fd, SOL_BLUETOOTH, BT_SECURITY, &sec, + sizeof(sec)) < 0) + return false; + + return true; +} + +static bool change_security(struct bt_att_chan *chan, uint8_t ecode) { int security; - if (att->io_sec_level != BT_ATT_SECURITY_AUTO) + if (chan->sec_level != BT_ATT_SECURITY_AUTO) return false; - security = bt_att_get_security(att, NULL); + security = bt_att_chan_get_security(chan); if (ecode == BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION && security < BT_ATT_SECURITY_MEDIUM) { @@ -622,14 +698,15 @@ static bool change_security(struct bt_att *att, uint8_t ecode) return false; } - return bt_att_set_security(att, security); + return bt_att_chan_set_security(chan, security); } -static bool handle_error_rsp(struct bt_att *att, uint8_t *pdu, +static bool handle_error_rsp(struct bt_att_chan *chan, uint8_t *pdu, ssize_t pdu_len, uint8_t *opcode) { + struct bt_att *att = chan->att; const struct bt_att_pdu_error_rsp *rsp; - struct att_send_op *op = att->pending_req; + struct att_send_op *op = chan->pending_req; if (pdu_len != sizeof(*rsp)) { *opcode = 0; @@ -641,7 +718,7 @@ static bool handle_error_rsp(struct bt_att *att, uint8_t *pdu, *opcode = rsp->opcode; /* Attempt to change security */ - if (!change_security(att, rsp->ecode)) + if (!change_security(chan, rsp->ecode)) return false; /* Remove timeout_id if outstanding */ @@ -653,16 +730,17 @@ static bool handle_error_rsp(struct bt_att *att, uint8_t *pdu, util_debug(att->debug_callback, att->debug_data, "Retrying operation %p", op); - att->pending_req = NULL; + chan->pending_req = NULL; /* Push operation back to request queue */ return queue_push_head(att->req_queue, op); } -static void handle_rsp(struct bt_att *att, uint8_t opcode, uint8_t *pdu, +static void handle_rsp(struct bt_att_chan *chan, uint8_t opcode, uint8_t *pdu, ssize_t pdu_len) { - struct att_send_op *op = att->pending_req; + struct bt_att *att = chan->att; + struct att_send_op *op = chan->pending_req; uint8_t req_opcode; uint8_t rsp_opcode; uint8_t *rsp_pdu = NULL; @@ -675,7 +753,7 @@ static void handle_rsp(struct bt_att *att, uint8_t opcode, uint8_t *pdu, if (!op) { util_debug(att->debug_callback, att->debug_data, "Received unexpected ATT response"); - io_shutdown(att->io); + io_shutdown(chan->io); return; } @@ -685,8 +763,8 @@ static void handle_rsp(struct bt_att *att, uint8_t opcode, uint8_t *pdu, */ if (opcode == BT_ATT_OP_ERROR_RSP) { /* Return if error response cause a retry */ - if (handle_error_rsp(att, pdu, pdu_len, &req_opcode)) { - wakeup_writer(att); + if (handle_error_rsp(chan, pdu, pdu_len, &req_opcode)) { + wakeup_chan_writer(chan, NULL); return; } } else if (!(req_opcode = get_req_opcode(opcode))) @@ -715,14 +793,15 @@ done: op->callback(rsp_opcode, rsp_pdu, rsp_pdu_len, op->user_data); destroy_att_send_op(op); - att->pending_req = NULL; + chan->pending_req = NULL; - wakeup_writer(att); + wakeup_chan_writer(chan, NULL); } -static void handle_conf(struct bt_att *att, uint8_t *pdu, ssize_t pdu_len) +static void handle_conf(struct bt_att_chan *chan, uint8_t *pdu, ssize_t pdu_len) { - struct att_send_op *op = att->pending_ind; + struct bt_att *att = chan->att; + struct att_send_op *op = chan->pending_ind; /* * Disconnect the bearer if the confirmation is unexpected or the PDU is @@ -731,7 +810,7 @@ static void handle_conf(struct bt_att *att, uint8_t *pdu, ssize_t pdu_len) if (!op || pdu_len) { util_debug(att->debug_callback, att->debug_data, "Received unexpected/invalid ATT confirmation"); - io_shutdown(att->io); + io_shutdown(chan->io); return; } @@ -739,9 +818,9 @@ static void handle_conf(struct bt_att *att, uint8_t *pdu, ssize_t pdu_len) op->callback(BT_ATT_OP_HANDLE_VAL_CONF, NULL, 0, op->user_data); destroy_att_send_op(op); - att->pending_ind = NULL; + chan->pending_ind = NULL; - wakeup_writer(att); + wakeup_chan_writer(chan, NULL); } struct notify_data { @@ -811,9 +890,10 @@ fail: return false; } -static void handle_notify(struct bt_att *att, uint8_t opcode, uint8_t *pdu, - ssize_t pdu_len) +static void handle_notify(struct bt_att_chan *chan, uint8_t opcode, + uint8_t *pdu, ssize_t pdu_len) { + struct bt_att *att = chan->att; const struct queue_entry *entry; bool found; @@ -845,7 +925,7 @@ static void handle_notify(struct bt_att *att, uint8_t opcode, uint8_t *pdu, * link since the MTU size is negotiated using L2CAP channel * configuration procedures. */ - if (bt_att_get_link_type(att) == BT_ATT_LINK_BREDR) { + if (bt_att_get_link_type(att) == BT_ATT_BREDR) { switch (opcode) { case BT_ATT_OP_MTU_REQ: goto not_supported; @@ -876,22 +956,23 @@ not_supported: static bool can_read_data(struct io *io, void *user_data) { - struct bt_att *att = user_data; + struct bt_att_chan *chan = user_data; + struct bt_att *att = chan->att; uint8_t opcode; uint8_t *pdu; ssize_t bytes_read; - bytes_read = read(att->fd, att->buf, att->mtu); + bytes_read = read(chan->fd, chan->buf, chan->mtu); if (bytes_read < 0) return false; - util_hexdump('>', att->buf, bytes_read, - att->debug_callback, att->debug_data); + util_hexdump('>', chan->buf, bytes_read, + att->debug_callback, att->debug_data); if (bytes_read < ATT_MIN_PDU_LEN) return true; - pdu = att->buf; + pdu = chan->buf; opcode = pdu[0]; bt_att_ref(att); @@ -901,12 +982,12 @@ static bool can_read_data(struct io *io, void *user_data) case ATT_OP_TYPE_RSP: util_debug(att->debug_callback, att->debug_data, "ATT response received: 0x%02x", opcode); - handle_rsp(att, opcode, pdu + 1, bytes_read - 1); + handle_rsp(chan, opcode, pdu + 1, bytes_read - 1); break; case ATT_OP_TYPE_CONF: util_debug(att->debug_callback, att->debug_data, "ATT confirmation received: 0x%02x", opcode); - handle_conf(att, pdu + 1, bytes_read - 1); + handle_conf(chan, pdu + 1, bytes_read - 1); break; case ATT_OP_TYPE_REQ: /* @@ -914,17 +995,17 @@ static bool can_read_data(struct io *io, void *user_data) * protocol was violated. Disconnect the bearer, which will * promptly notify the upper layer via disconnect handlers. */ - if (att->in_req) { + if (chan->in_req) { util_debug(att->debug_callback, att->debug_data, "Received request while another is " "pending: 0x%02x", opcode); - io_shutdown(att->io); - bt_att_unref(att); + io_shutdown(chan->io); + bt_att_unref(chan->att); return false; } - att->in_req = true; + chan->in_req = true; /* fall through */ case ATT_OP_TYPE_CMD: case ATT_OP_TYPE_NOT: @@ -937,7 +1018,7 @@ static bool can_read_data(struct io *io, void *user_data) */ util_debug(att->debug_callback, att->debug_data, "ATT PDU received: 0x%02x", opcode); - handle_notify(att, opcode, pdu + 1, bytes_read - 1); + handle_notify(chan, opcode, pdu + 1, bytes_read - 1); break; } @@ -973,21 +1054,8 @@ static bool is_io_l2cap_based(int fd) static void bt_att_free(struct bt_att *att) { - if (att->pending_req) - destroy_att_send_op(att->pending_req); - - if (att->pending_ind) - destroy_att_send_op(att->pending_ind); - - io_destroy(att->io); bt_crypto_unref(att->crypto); - queue_destroy(att->req_queue, NULL); - queue_destroy(att->ind_queue, NULL); - queue_destroy(att->write_queue, NULL); - queue_destroy(att->notify_list, NULL); - queue_destroy(att->disconn_list, NULL); - if (att->timeout_destroy) att->timeout_destroy(att->timeout_data); @@ -997,7 +1065,12 @@ static void bt_att_free(struct bt_att *att) free(att->local_sign); free(att->remote_sign); - free(att->buf); + queue_destroy(att->req_queue, NULL); + queue_destroy(att->ind_queue, NULL); + queue_destroy(att->write_queue, NULL); + queue_destroy(att->notify_list, NULL); + queue_destroy(att->disconn_list, NULL); + queue_destroy(att->chans, bt_att_chan_free); free(att); } @@ -1014,60 +1087,101 @@ static uint16_t get_l2cap_mtu(int fd) return l2o.omtu; } -struct bt_att *bt_att_new(int fd, bool ext_signed) +static uint8_t io_get_type(int fd) { - struct bt_att *att; + struct sockaddr_l2 src; + socklen_t len; - if (fd < 0) - return NULL; + if (!is_io_l2cap_based(fd)) + return BT_ATT_LOCAL; - att = new0(struct bt_att, 1); - att->fd = fd; + len = sizeof(src); + memset(&src, 0, len); + if (getsockname(fd, (void *)&src, &len) < 0) + return -errno; - att->io = io_new(fd); - if (!att->io) - goto fail; + if (src.l2_bdaddr_type == BDADDR_BREDR) + return BT_ATT_BREDR; - /* crypto is optional, if not available leave it NULL */ - if (!ext_signed) - att->crypto = bt_crypto_new(); + return BT_ATT_LE; +} - att->req_queue = queue_new(); - att->ind_queue = queue_new(); - att->write_queue = queue_new(); - att->notify_list = queue_new(); - att->disconn_list = queue_new(); +static struct bt_att_chan *bt_att_chan_new(int fd, uint8_t type) +{ + struct bt_att_chan *chan; - if (!io_set_read_handler(att->io, can_read_data, att, NULL)) + if (fd < 0) + return NULL; + + chan = new0(struct bt_att_chan, 1); + chan->fd = fd; + + chan->io = io_new(fd); + if (!chan->io) goto fail; - if (!io_set_disconnect_handler(att->io, disconnect_cb, att, NULL)) + if (!io_set_read_handler(chan->io, can_read_data, chan, NULL)) goto fail; - att->io_on_l2cap = is_io_l2cap_based(att->fd); - if (!att->io_on_l2cap) - att->io_sec_level = BT_ATT_SECURITY_LOW; + if (!io_set_disconnect_handler(chan->io, disconnect_cb, chan, NULL)) + goto fail; - if (bt_att_get_link_type(att) == BT_ATT_LINK_BREDR) - att->mtu = get_l2cap_mtu(att->fd); - else - att->mtu = BT_ATT_DEFAULT_LE_MTU; + chan->type = type; + switch (chan->type) { + case BT_ATT_LOCAL: + chan->sec_level = BT_ATT_SECURITY_LOW; + /* fall through */ + case BT_ATT_LE: + chan->mtu = BT_ATT_DEFAULT_LE_MTU; + break; + default: + chan->mtu = get_l2cap_mtu(chan->fd); + } - if (att->mtu < BT_ATT_DEFAULT_LE_MTU) + if (chan->mtu < BT_ATT_DEFAULT_LE_MTU) goto fail; - att->buf = malloc(att->mtu); - if (!att->buf) + chan->buf = malloc(chan->mtu); + if (!chan->buf) goto fail; - return bt_att_ref(att); + return chan; fail: - bt_att_free(att); + bt_att_chan_free(chan); return NULL; } +struct bt_att *bt_att_new(int fd, bool ext_signed) +{ + struct bt_att *att; + struct bt_att_chan *chan; + + chan = bt_att_chan_new(fd, io_get_type(fd)); + if (!chan) + return NULL; + + att = new0(struct bt_att, 1); + att->chans = queue_new(); + att->mtu = chan->mtu; + + queue_push_head(att->chans, chan); + chan->att = att; + + /* crypto is optional, if not available leave it NULL */ + if (!ext_signed) + att->crypto = bt_crypto_new(); + + att->req_queue = queue_new(); + att->ind_queue = queue_new(); + att->write_queue = queue_new(); + att->notify_list = queue_new(); + att->disconn_list = queue_new(); + + return bt_att_ref(att); +} + struct bt_att *bt_att_ref(struct bt_att *att) { if (!att) @@ -1094,18 +1208,67 @@ void bt_att_unref(struct bt_att *att) bool bt_att_set_close_on_unref(struct bt_att *att, bool do_close) { - if (!att || !att->io) + const struct queue_entry *entry; + + if (!att) return false; - return io_set_close_on_destroy(att->io, do_close); + att->close_on_unref = do_close; + + for (entry = queue_get_entries(att->chans); entry; + entry = entry->next) { + struct bt_att_chan *chan = entry->data; + + if (!io_set_close_on_destroy(chan->io, do_close)) + return false; + } + + return true; +} + +int bt_att_attach_fd(struct bt_att *att, int fd) +{ + struct bt_att_chan *chan; + + if (!att || fd < 0) + return -EINVAL; + + chan = bt_att_chan_new(fd, BT_ATT_EATT); + if (!chan) + return -EINVAL; + + queue_push_tail(att->chans, chan); + chan->att = att; + + if (chan->mtu > att->mtu) + att->mtu = chan->mtu; + + io_set_close_on_destroy(chan->io, att->close_on_unref); + + return 0; } int bt_att_get_fd(struct bt_att *att) { + struct bt_att_chan *chan; + if (!att) return -1; - return att->fd; + if (queue_isempty(att->chans)) + return -ENOTCONN; + + chan = queue_peek_head(att->chans); + + return chan->fd; +} + +int bt_att_get_channels(struct bt_att *att) +{ + if (!att) + return 0; + + return queue_length(att->chans); } bool bt_att_set_debug(struct bt_att *att, bt_att_debug_func_t callback, @@ -1134,6 +1297,7 @@ uint16_t bt_att_get_mtu(struct bt_att *att) bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu) { + struct bt_att_chan *chan; void *buf; if (!att) @@ -1142,38 +1306,37 @@ bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu) if (mtu < BT_ATT_DEFAULT_LE_MTU) return false; + chan = queue_peek_head(att->chans); + if (!chan) + return -ENOTCONN; + buf = malloc(mtu); if (!buf) return false; - free(att->buf); + free(chan->buf); + + chan->mtu = mtu; + chan->buf = buf; - att->mtu = mtu; - att->buf = buf; + if (chan->mtu > att->mtu) + att->mtu = chan->mtu; return true; } uint8_t bt_att_get_link_type(struct bt_att *att) { - struct sockaddr_l2 src; - socklen_t len; + struct bt_att_chan *chan; if (!att) return -EINVAL; - if (!att->io_on_l2cap) - return BT_ATT_LINK_LOCAL; + chan = queue_peek_head(att->chans); + if (!chan) + return -ENOTCONN; - len = sizeof(src); - memset(&src, 0, len); - if (getsockname(att->fd, (void *)&src, &len) < 0) - return -errno; - - if (src.l2_bdaddr_type == BDADDR_BREDR) - return BT_ATT_LINK_BREDR; - - return BT_ATT_LINK_LE; + return chan->type; } bool bt_att_set_timeout_cb(struct bt_att *att, bt_att_timeout_func_t callback, @@ -1200,7 +1363,7 @@ unsigned int bt_att_register_disconnect(struct bt_att *att, { struct att_disconn *disconn; - if (!att || !att->io) + if (!att || queue_isempty(att->chans)) return 0; disconn = new0(struct att_disconn, 1); @@ -1229,7 +1392,7 @@ bool bt_att_unregister_disconnect(struct bt_att *att, unsigned int id) return false; /* Check if disconnect is running */ - if (!att->io) { + if (!queue_isempty(att->chans)) { disconn = queue_find(att->disconn_list, match_disconn_id, UINT_TO_PTR(id)); if (!disconn) @@ -1256,7 +1419,7 @@ unsigned int bt_att_send(struct bt_att *att, uint8_t opcode, struct att_send_op *op; bool result; - if (!att || !att->io) + if (!att || queue_isempty(att->chans)) return 0; op = create_att_send_op(att, opcode, pdu, length, callback, user_data, @@ -1308,21 +1471,31 @@ static bool match_op_id(const void *a, const void *b) bool bt_att_cancel(struct bt_att *att, unsigned int id) { + const struct queue_entry *entry; struct att_send_op *op; if (!att || !id) return false; - if (att->pending_req && att->pending_req->id == id) { - /* Don't cancel the pending request; remove it's handlers */ - cancel_att_send_op(att->pending_req); - return true; - } + for (entry = queue_get_entries(att->chans); entry; + entry = entry->next) { + struct bt_att_chan *chan = entry->data; - if (att->pending_ind && att->pending_ind->id == id) { - /* Don't cancel the pending indication; remove it's handlers */ - cancel_att_send_op(att->pending_ind); - return true; + if (chan->pending_req && chan->pending_req->id == id) { + /* Don't cancel the pending request; remove it's + * handlers + */ + cancel_att_send_op(chan->pending_req); + return true; + } + + if (chan->pending_ind && chan->pending_ind->id == id) { + /* Don't cancel the pending indication; remove it's + * handlers. + */ + cancel_att_send_op(chan->pending_ind); + return true; + } } op = queue_remove_if(att->req_queue, match_op_id, UINT_TO_PTR(id)); @@ -1350,6 +1523,8 @@ done: bool bt_att_cancel_all(struct bt_att *att) { + const struct queue_entry *entry; + if (!att) return false; @@ -1357,13 +1532,22 @@ bool bt_att_cancel_all(struct bt_att *att) queue_remove_all(att->ind_queue, NULL, NULL, destroy_att_send_op); queue_remove_all(att->write_queue, NULL, NULL, destroy_att_send_op); - if (att->pending_req) - /* Don't cancel the pending request; remove it's handlers */ - cancel_att_send_op(att->pending_req); - - if (att->pending_ind) - /* Don't cancel the pending request; remove it's handlers */ - cancel_att_send_op(att->pending_ind); + for (entry = queue_get_entries(att->chans); entry; + entry = entry->next) { + struct bt_att_chan *chan = entry->data; + + if (chan->pending_req) + /* Don't cancel the pending request; remove it's + * handlers + */ + cancel_att_send_op(chan->pending_req); + + if (chan->pending_ind) + /* Don't cancel the pending request; remove it's + * handlers + */ + cancel_att_send_op(chan->pending_ind); + } return true; } @@ -1424,7 +1608,7 @@ unsigned int bt_att_register(struct bt_att *att, uint8_t opcode, { struct att_notify *notify; - if (!att || !callback || !att->io) + if (!att || !callback || queue_isempty(att->chans)) return 0; notify = new0(struct att_notify, 1); @@ -1475,51 +1659,39 @@ bool bt_att_unregister_all(struct bt_att *att) int bt_att_get_security(struct bt_att *att, uint8_t *enc_size) { - struct bt_security sec; - socklen_t len; + struct bt_att_chan *chan; + int ret; if (!att) return -EINVAL; - if (!att->io_on_l2cap) { - if (enc_size) - *enc_size = att->enc_size; + chan = queue_peek_head(att->chans); + if (!chan) + return -ENOTCONN; - return att->io_sec_level; - } - - memset(&sec, 0, sizeof(sec)); - len = sizeof(sec); - if (getsockopt(att->fd, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) < 0) - return -EIO; + ret = bt_att_chan_get_security(chan); + if (ret < 0) + return ret; if (enc_size) *enc_size = att->enc_size; - return sec.level; + return ret; } bool bt_att_set_security(struct bt_att *att, int level) { - struct bt_security sec; + struct bt_att_chan *chan; if (!att || level < BT_ATT_SECURITY_AUTO || level > BT_ATT_SECURITY_HIGH) return false; - if (!att->io_on_l2cap) { - att->io_sec_level = level; - return true; - } + chan = queue_peek_head(att->chans); + if (!chan) + return -ENOTCONN; - memset(&sec, 0, sizeof(sec)); - sec.level = level; - - if (setsockopt(att->fd, SOL_BLUETOOTH, BT_SECURITY, &sec, - sizeof(sec)) < 0) - return false; - - return true; + return bt_att_chan_set_security(chan, level); } void bt_att_set_enc_key_size(struct bt_att *att, uint8_t enc_size) diff --git a/src/shared/att.h b/src/shared/att.h index 49d93269b..110700846 100644 --- a/src/shared/att.h +++ b/src/shared/att.h @@ -37,6 +37,10 @@ bool bt_att_set_close_on_unref(struct bt_att *att, bool do_close); int bt_att_get_fd(struct bt_att *att); +int bt_att_attach_fd(struct bt_att *att, int fd); + +int bt_att_get_channels(struct bt_att *att); + typedef void (*bt_att_response_func_t)(uint8_t opcode, const void *pdu, uint16_t length, void *user_data); typedef void (*bt_att_notify_func_t)(uint8_t opcode, const void *pdu, diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c index 29254cb61..3ce126485 100644 --- a/src/shared/gatt-client.c +++ b/src/shared/gatt-client.c @@ -1909,7 +1909,7 @@ static bool gatt_client_init(struct bt_gatt_client *client, uint16_t mtu) * the MTU size is negotiated using L2CAP channel configuration * procedures. */ - if (bt_att_get_link_type(client->att) == BT_ATT_LINK_BREDR) + if (bt_att_get_link_type(client->att) == BT_ATT_BREDR) goto discover; /* Check if MTU needs to be send */ From patchwork Fri Feb 28 23:46:56 2020 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: 197330 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 83692C3F2D2 for ; Fri, 28 Feb 2020 23:47:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4EB8E246B5 for ; Fri, 28 Feb 2020 23:47:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="XZl4iA/b" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726788AbgB1XrN (ORCPT ); Fri, 28 Feb 2020 18:47:13 -0500 Received: from mail-pg1-f193.google.com ([209.85.215.193]:41293 "EHLO mail-pg1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725957AbgB1XrN (ORCPT ); Fri, 28 Feb 2020 18:47:13 -0500 Received: by mail-pg1-f193.google.com with SMTP id b1so2291633pgm.8 for ; Fri, 28 Feb 2020 15:47:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=F0EYRJheUMHXrROxyDRP4RYQ+UKzYUGuYTVdPdCLH+E=; b=XZl4iA/b7jylrHnuYNeX0LqAHO/fD+P4tLBeMhHPgUe04qJ0O2hI6nACzmiOmACb2v nMhKHMHAT3YZ1+5gzxLljUIyPX4kTYLCaijQ81Q0wVxB74Ep9wxotLI0KBBD+vYttWX1 gheI6aDQOCV0rCd9tcAfyEhgST5lZFgCuZpbzGmxjceEriHp+SxjwHTKt4plvaQSDNmV dO2QVFju0Jg8+dUDq7zs6UgKRRpFHiP3RIubDbPqg+hAKkbIznmu2Bwr0vHRj3/ZjJjH WLCsLazVTseADV9YbbgX8UtzMxgrzPYBVeUwSGqyZ45C81X2CNpDb08wDDVRUAcWEyBK +KgQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=F0EYRJheUMHXrROxyDRP4RYQ+UKzYUGuYTVdPdCLH+E=; b=MS4YaETaFBHtp/NrRIDB6jPuilOHGkl+4b7ayFHTOVznrJk86hmcHDFYoCUIhr/rjU bArh4cJxNOz8oLlNAd/RfQ/2Jlt5Fvp5pyufL6uYP0GXlTJ+Eb+ciSAqYg1LFJw7mhgL m7/HuE9LJ8sRzMHLmqAYp8Pb/weobcNBn58NqSB7b5BM9lCyoGsCf9YqzWFdY2ddiHyW H4RV98zR35hAQ+lSXD2VekBNoQU528zSCQfDvEjAMVyuO4ffbTqossJOJHMgnfuwVu7g 4AjMojVyIdjWVhNKmS8t7E/vEVOLwMQLPHHifCReSXLBP8ZvAfgITZaAwgJWFnnq9rdJ XESQ== X-Gm-Message-State: APjAAAWMLXoATE5w6+2r69iSC6OHYqvtTn5+lWQsQOwFl4/2A7AvLq8P /NAFyKDJasD37IuEQ8vgrgKh71DNvHk= X-Google-Smtp-Source: APXvYqxb3gumvOZHNpm1UqtRR0Q9BN0T2DlO3pmYUnAX3L/hS+V0LGQ/0KGpnVDYrwzPfDtQ43Tkog== X-Received: by 2002:a63:e20a:: with SMTP id q10mr5725388pgh.331.1582933630570; Fri, 28 Feb 2020 15:47:10 -0800 (PST) Received: from localhost.localdomain (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id q13sm13643954pfn.162.2020.02.28.15.47.09 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2020 15:47:10 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH v2 07/12] shared/gatt-server: Add support for Read Multiple Variable Length Date: Fri, 28 Feb 2020 15:46:56 -0800 Message-Id: <20200228234701.14614-8-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200228234701.14614-1-luiz.dentz@gmail.com> References: <20200228234701.14614-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz The Read Multiple Variable Length Request is used to request that the server read two or more values of a set of attributes that have a variable or unknown value length and return their values in a Read Multiple Variable Length Response. --- src/shared/att-types.h | 2 + src/shared/gatt-server.c | 113 ++++++++++++++++++++++++++------------- 2 files changed, 79 insertions(+), 36 deletions(-) diff --git a/src/shared/att-types.h b/src/shared/att-types.h index 7b88e7d92..cc9cc9fd6 100644 --- a/src/shared/att-types.h +++ b/src/shared/att-types.h @@ -75,6 +75,8 @@ #define BT_ATT_OP_HANDLE_VAL_NOT 0x1B #define BT_ATT_OP_HANDLE_VAL_IND 0x1D #define BT_ATT_OP_HANDLE_VAL_CONF 0x1E +#define BT_ATT_OP_READ_MULT_VL_REQ 0x20 +#define BT_ATT_OP_READ_MULT_VL_RSP 0x21 /* Packed struct definitions for ATT protocol PDUs */ /* TODO: Complete these definitions for all opcodes */ diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c index ee0058486..8b18cb21f 100644 --- a/src/shared/gatt-server.c +++ b/src/shared/gatt-server.c @@ -102,6 +102,7 @@ struct bt_gatt_server { unsigned int read_id; unsigned int read_blob_id; unsigned int read_multiple_id; + unsigned int read_multiple_vl_id; unsigned int prep_write_id; unsigned int exec_write_id; @@ -136,6 +137,7 @@ static void bt_gatt_server_free(struct bt_gatt_server *server) bt_att_unregister(server->att, server->read_id); bt_att_unregister(server->att, server->read_blob_id); bt_att_unregister(server->att, server->read_multiple_id); + bt_att_unregister(server->att, server->read_multiple_vl_id); bt_att_unregister(server->att, server->prep_write_id); bt_att_unregister(server->att, server->exec_write_id); @@ -1013,9 +1015,10 @@ static void read_blob_cb(struct bt_att_chan *chan, uint8_t opcode, handle_read_req(chan, server, opcode, handle, offset); } -struct read_multiple_resp_data { +struct read_mult_data { struct bt_att_chan *chan; struct bt_gatt_server *server; + uint8_t opcode; uint16_t *handles; size_t cur_handle; size_t num_handles; @@ -1024,7 +1027,7 @@ struct read_multiple_resp_data { size_t mtu; }; -static void read_multiple_resp_data_free(struct read_multiple_resp_data *data) +static void read_mult_data_free(struct read_mult_data *data) { free(data->handles); free(data->rsp_data); @@ -1035,15 +1038,16 @@ static void read_multiple_complete_cb(struct gatt_db_attribute *attr, int err, const uint8_t *value, size_t len, void *user_data) { - struct read_multiple_resp_data *data = user_data; + struct read_mult_data *data = user_data; struct gatt_db_attribute *next_attr; uint16_t handle = gatt_db_attribute_get_handle(attr); uint8_t ecode; + uint16_t length; if (err != 0) { - bt_att_chan_send_error_rsp(data->chan, - BT_ATT_OP_READ_MULT_REQ, handle, err); - read_multiple_resp_data_free(data); + bt_att_chan_send_error_rsp(data->chan, data->opcode, handle, + err); + read_mult_data_free(data); return; } @@ -1051,29 +1055,45 @@ static void read_multiple_complete_cb(struct gatt_db_attribute *attr, int err, BT_ATT_PERM_READ_AUTHEN | BT_ATT_PERM_READ_ENCRYPT); if (ecode) { - bt_att_chan_send_error_rsp(data->chan, - BT_ATT_OP_READ_MULT_REQ, handle, ecode); - read_multiple_resp_data_free(data); + bt_att_chan_send_error_rsp(data->chan, data->opcode, handle, + ecode); + read_mult_data_free(data); return; } - len = MIN(len, data->mtu - data->length - 1); + length = data->opcode == BT_ATT_OP_READ_MULT_VL_REQ ? + MIN(len, data->mtu - data->length - 3) : + MIN(len, data->mtu - data->length - 1); - memcpy(data->rsp_data + data->length, value, len); - data->length += len; + if (data->opcode == BT_ATT_OP_READ_MULT_VL_REQ) { + /* The Length Value Tuple List may be truncated within the first + * two octets of a tuple due to the size limits of the current + * ATT_MTU. + */ + put_le16(len, data->rsp_data + data->length); + data->length += 2; + } + + memcpy(data->rsp_data + data->length, value, length); + data->length += length; data->cur_handle++; - if ((data->length >= data->mtu - 1) || - (data->cur_handle == data->num_handles)) { - bt_att_chan_send_rsp(data->chan, BT_ATT_OP_READ_MULT_RSP, + len = data->opcode == BT_ATT_OP_READ_MULT_VL_REQ ? + data->mtu - data->length - 3 : data->mtu - data->length - 1; + + if (!len || (data->cur_handle == data->num_handles)) { + bt_att_chan_send_rsp(data->chan, data->opcode + 1, data->rsp_data, data->length); - read_multiple_resp_data_free(data); + read_mult_data_free(data); return; } util_debug(data->server->debug_callback, data->server->debug_data, - "Read Multiple Req - #%zu of %zu: 0x%04x", + "%s Req - #%zu of %zu: 0x%04x", + data->opcode == BT_ATT_OP_READ_MULT_REQ ? + "Read Multiple" : + "Read Multiple Variable Length", data->cur_handle + 1, data->num_handles, data->handles[data->cur_handle]); @@ -1085,7 +1105,7 @@ static void read_multiple_complete_cb(struct gatt_db_attribute *attr, int err, BT_ATT_OP_READ_MULT_REQ, data->handles[data->cur_handle], BT_ATT_ERROR_INVALID_HANDLE); - read_multiple_resp_data_free(data); + read_mult_data_free(data); return; } @@ -1096,17 +1116,39 @@ static void read_multiple_complete_cb(struct gatt_db_attribute *attr, int err, BT_ATT_OP_READ_MULT_REQ, data->handles[data->cur_handle], BT_ATT_ERROR_UNLIKELY); - read_multiple_resp_data_free(data); + read_mult_data_free(data); } } +static struct read_mult_data *read_mult_data_new(struct bt_gatt_server *server, + struct bt_att_chan *chan, + uint8_t opcode, + uint16_t num_handles) +{ + struct read_mult_data *data; + + data = new0(struct read_mult_data, 1); + data->chan = chan; + data->opcode = opcode; + data->handles = new0(uint16_t, num_handles); + data->rsp_data = NULL; + data->server = server; + data->num_handles = num_handles; + data->cur_handle = 0; + data->mtu = bt_att_get_mtu(server->att); + data->length = 0; + data->rsp_data = new0(uint8_t, data->mtu - 1); + + return data; +} + static void read_multiple_cb(struct bt_att_chan *chan, uint8_t opcode, const void *pdu, uint16_t length, void *user_data) { struct bt_gatt_server *server = user_data; struct gatt_db_attribute *attr; - struct read_multiple_resp_data *data = NULL; + struct read_mult_data *data = NULL; uint8_t ecode = BT_ATT_ERROR_UNLIKELY; size_t i = 0; @@ -1115,27 +1157,17 @@ static void read_multiple_cb(struct bt_att_chan *chan, uint8_t opcode, goto error; } - data = new0(struct read_multiple_resp_data, 1); - data->chan = chan; - data->handles = NULL; - data->rsp_data = NULL; - data->server = server; - data->num_handles = length / 2; - data->cur_handle = 0; - data->mtu = bt_att_get_mtu(server->att); - data->length = 0; - data->rsp_data = malloc(data->mtu - 1); - - if (!data->rsp_data) + data = read_mult_data_new(server, chan, opcode, length / 2); + if (!data) goto error; - data->handles = new0(uint16_t, data->num_handles); - for (i = 0; i < data->num_handles; i++) data->handles[i] = get_le16(pdu + i * 2); util_debug(server->debug_callback, server->debug_data, - "Read Multiple Req - %zu handles, 1st: 0x%04x", + "%s Req - %zu handles, 1st: 0x%04x", + data->opcode == BT_ATT_OP_READ_MULT_REQ ? + "Read Multiple" : "Read Multiple Variable Length", data->num_handles, data->handles[0]); attr = gatt_db_get_attribute(server->db, data->handles[0]); @@ -1151,7 +1183,7 @@ static void read_multiple_cb(struct bt_att_chan *chan, uint8_t opcode, error: if (data) - read_multiple_resp_data_free(data); + read_mult_data_free(data); bt_att_chan_send_error_rsp(chan, opcode, 0, ecode); } @@ -1588,6 +1620,15 @@ static bool gatt_server_register_att_handlers(struct bt_gatt_server *server) if (!server->read_multiple_id) return false; + /* Read Multiple Variable Length Request */ + server->read_multiple_vl_id = bt_att_register(server->att, + BT_ATT_OP_READ_MULT_VL_REQ, + read_multiple_cb, + server, NULL); + + if (!server->read_multiple_vl_id) + return false; + /* Prepare Write Request */ server->prep_write_id = bt_att_register(server->att, BT_ATT_OP_PREP_WRITE_REQ, From patchwork Fri Feb 28 23:46:57 2020 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: 197329 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 924E5C3F2D4 for ; Fri, 28 Feb 2020 23:47:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 69C9C246B5 for ; Fri, 28 Feb 2020 23:47:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mUcOj83b" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726838AbgB1XrP (ORCPT ); Fri, 28 Feb 2020 18:47:15 -0500 Received: from mail-pl1-f196.google.com ([209.85.214.196]:42992 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726798AbgB1XrO (ORCPT ); Fri, 28 Feb 2020 18:47:14 -0500 Received: by mail-pl1-f196.google.com with SMTP id u3so1826775plr.9 for ; Fri, 28 Feb 2020 15:47:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=QWDfGgp0E1rqcdY0x4qxjaOMAPigahCylDGC8zfCPCs=; b=mUcOj83btugphxtskZuyFh/hffkA+yTaBHTdo1pYOYxrveUsrI78LYQsl1ANX1bqjD ZSnXJk+mjnsu5FKRl9J59jHMgTKEP7r04rlLuAV6TUH0+rufAHpXLR2hNek9Sn5wbcIq 5rJNI2pH2TSew9zcJ1xg1PSkksbEn/SW7Nvgnk8htv5OAAY6OedHoTk2DZfj4j+uEBW5 NQWQctazIwcUQpb3/4ZCoHGsi7XoASdqkE5X6fCV6a/0Jt6pK9JHZIzqz93TUtNuzKjy 9ASu5ozPFdDFy9d5se7RIN2H3L7mFCu9/wySExJl36ynWPeNwv5ta5mL3SvMzjKxPp3e vlkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=QWDfGgp0E1rqcdY0x4qxjaOMAPigahCylDGC8zfCPCs=; b=bgLQtyYwvwqYQaTGmsQM/xXa33ClXrhDZvP4C2U3X4GXpfnXiEzG1TZz4r6NqumV+J Ftkl+evZTtZ5LBsLmHMW+73A12r2jKbZYuLPRmKztRdqNVlGJBPtUqg7NX+fVuNMy8ew Z6ZXSwvzfmCfrF23dpiQx78iuPSHui8cYjz1646iFh3nABTaLmMLIZZhjNIZuejKO827 GajnsFOVzFRi7a4K5bT7Djvdfgm2X/4iKBnKBGA41dugFmHQC2AWJ7D9tXlKCzbC5Zjd ho+fNt3UPhme6WZIXAfCbw5+nerWen1qUfhfq72w9eIjzTHRsU+KUp2N3s8OdzN8A/ZS 8LYw== X-Gm-Message-State: ANhLgQ00aooePaG3hrR5PS0Y3VmZU5jm9RLdeF6QyzgCkZ4AvG0vY+dI fIYz/VMHYOe4RtRDqiGsvem5QNnzxPI= X-Google-Smtp-Source: ADFU+vu9JfHadDKuXms5KfoT3PsGOmDgWr/jxwHK07pZ+EYpqbwHtk+s+CHx2vhumVk6j4bakIndwQ== X-Received: by 2002:a17:90a:3a86:: with SMTP id b6mr1403835pjc.96.1582933631765; Fri, 28 Feb 2020 15:47:11 -0800 (PST) Received: from localhost.localdomain (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id q13sm13643954pfn.162.2020.02.28.15.47.10 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2020 15:47:11 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH v2 08/12] shared/gatt-client: Add support for Read Multiple Variable Length Date: Fri, 28 Feb 2020 15:46:57 -0800 Message-Id: <20200228234701.14614-9-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200228234701.14614-1-luiz.dentz@gmail.com> References: <20200228234701.14614-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz The Read Multiple Variable Length Request is used to request that the server read two or more values of a set of attributes that have a variable or unknown value length and return their values in a Read Multiple Variable Length Response. --- src/shared/gatt-client.c | 42 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c index 2c5fe14dc..5b6723f97 100644 --- a/src/shared/gatt-client.c +++ b/src/shared/gatt-client.c @@ -2642,7 +2642,9 @@ static void read_multiple_cb(uint8_t opcode, const void *pdu, uint16_t length, uint8_t att_ecode; bool success; - if (opcode != BT_ATT_OP_READ_MULT_RSP || (!pdu && length)) { + if ((opcode != BT_ATT_OP_READ_MULT_RSP && + opcode != BT_ATT_OP_READ_MULT_VL_RSP) || + (!pdu && length)) { success = false; if (opcode == BT_ATT_OP_ERROR_RSP) @@ -2657,8 +2659,36 @@ static void read_multiple_cb(uint8_t opcode, const void *pdu, uint16_t length, att_ecode = 0; } - if (op->callback) + if (!op->callback) + return; + + if (opcode == BT_ATT_OP_READ_MULT_RSP || att_ecode) { op->callback(success, att_ecode, pdu, length, op->user_data); + return; + } + + if (length < 2) { + op->callback(success, att_ecode, pdu, length, op->user_data); + return; + } + + /* Parse response */ + while (length >= 2) { + uint16_t len; + + len = get_le16(pdu); + length -= 2; + pdu += 2; + + /* The Length Value Tuple List may be truncated within the + * first two octets of a tuple due to the size limits of the + * current ATT_MTU. + */ + if (len > length) + length = len; + + op->callback(success, att_ecode, pdu, len, op->user_data); + } } unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client, @@ -2670,6 +2700,7 @@ unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client, uint8_t pdu[num_handles * 2]; struct request *req; struct read_op *op; + uint8_t opcode; int i; if (!client) @@ -2699,8 +2730,11 @@ unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client, for (i = 0; i < num_handles; i++) put_le16(handles[i], pdu + (2 * i)); - req->att_id = bt_att_send(client->att, BT_ATT_OP_READ_MULT_REQ, - pdu, sizeof(pdu), + opcode = bt_gatt_client_get_features(client) & + BT_GATT_CHRC_CLI_FEAT_EATT ? BT_ATT_OP_READ_MULT_VL_REQ : + BT_ATT_OP_READ_MULT_REQ; + + req->att_id = bt_att_send(client->att, opcode, pdu, sizeof(pdu), read_multiple_cb, req, request_unref); if (!req->att_id) { From patchwork Fri Feb 28 23:47:00 2020 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: 197328 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.0 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C3BC5C3F2D2 for ; Fri, 28 Feb 2020 23:47:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 92867246B6 for ; Fri, 28 Feb 2020 23:47:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="e1MPxMf/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726857AbgB1XrR (ORCPT ); Fri, 28 Feb 2020 18:47:17 -0500 Received: from mail-pg1-f196.google.com ([209.85.215.196]:41301 "EHLO mail-pg1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726845AbgB1XrQ (ORCPT ); Fri, 28 Feb 2020 18:47:16 -0500 Received: by mail-pg1-f196.google.com with SMTP id b1so2291721pgm.8 for ; Fri, 28 Feb 2020 15:47:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=71j6KIh4O1bMSaDqDl28Qe8IFycvbdYvPA383k/CA+I=; b=e1MPxMf/ShhmI4JzT0UYt3+mUh0qpkuHA4nqMhnSFZ6WlSIj3DGK/v69QPw/6J4/KJ 2i7QjCk1R57r+/bZDZcwnqhpHGHEBqByq2FChrD0Ehi7WOUW56Me5OlJ8mL1nZhPhFyV 7y16OBR75snJapXp7KwZRdibMvFDV488bOUk4wy1ARpltuB+/af1kEL/WOwg5MrBM9eT 1L7EQszOdP4LuJPytFeYt4zpUqIU5TWPepYKBQG1okRjtZjfoRiVEtjkHQRdGsvKCFqD TXoMizG947axpiBI7qvanEfCuJLaAxU7X+MayvSGRlsmg9gI7NtnZHKu6bLEz+12ZYMX 529A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=71j6KIh4O1bMSaDqDl28Qe8IFycvbdYvPA383k/CA+I=; b=eYKGRFY+dVrVDr6TgYxxP4GFl4GothxShUP72GaK4ZxRWgjiVpp3Gjk4M3C8sB/oar 0ao9vJdywZ4VRNM9K7nhqE5GcOH+G/Wp73dpGn2jIsHJnvk0zw0wtAQyirBQdvqzrnex D5rVe9kLloEzyZeolBHusJDPb3PVorkuPFPjLtwyWzPkrP0kobt3MB8LPi30VmV+zCjr eTsI3Sm0dK2mDhZKitc8fTsLbpS5sX+uP+ayvTGXnj8rIyNW6Hi+Q7N4aGUpBpjxNNfz xyuemfOLjNZ0DAYeAfvOl0EGC5iGgOD6K/FfW2xxSXTbMFsSHpGcbX2s8hTn1v6LUhxh AFMA== X-Gm-Message-State: APjAAAVkgJSLfVCUDTEaO36QpTd7Ipy/JZRMhhwtpcDoZaKPEqqQNqct QRyGD+UXFbb4l7QTofeAmjrs6GEErt4= X-Google-Smtp-Source: APXvYqy3JCtxwvKMG1akJpnWwJCfitFbk23IBwhatCcu0SyP6sI/a9XoymcAWZCNa6sb6UFLcoL1VQ== X-Received: by 2002:a62:3808:: with SMTP id f8mr6868661pfa.30.1582933635323; Fri, 28 Feb 2020 15:47:15 -0800 (PST) Received: from localhost.localdomain (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id q13sm13643954pfn.162.2020.02.28.15.47.14 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2020 15:47:14 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH v2 11/12] core: Add support for setting the number of GATT bearers Date: Fri, 28 Feb 2020 15:47:00 -0800 Message-Id: <20200228234701.14614-12-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200228234701.14614-1-luiz.dentz@gmail.com> References: <20200228234701.14614-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz This adds option to set the numbers of GATT Channels/Bearers to be connected in main.conf. --- src/device.c | 5 +++++ src/gatt-client.c | 8 +++++--- src/gatt-database.c | 12 ++++++++++-- src/hcid.h | 1 + src/main.c | 14 ++++++++++++++ src/main.conf | 5 +++++ 6 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/device.c b/src/device.c index c86e9a64d..7e3c2b215 100644 --- a/src/device.c +++ b/src/device.c @@ -5049,6 +5049,11 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io) } if (dev->att) { + if (main_opts.gatt_channels == bt_att_get_channels(dev->att)) { + DBG("EATT channel limit reached"); + return false; + } + if (!bt_att_attach_fd(dev->att, g_io_channel_unix_get_fd(io))) { DBG("EATT channel connected"); g_io_channel_set_close_on_unref(io, FALSE); diff --git a/src/gatt-client.c b/src/gatt-client.c index aa77661ad..958ce5f9b 100644 --- a/src/gatt-client.c +++ b/src/gatt-client.c @@ -59,8 +59,6 @@ #define GATT_CHARACTERISTIC_IFACE "org.bluez.GattCharacteristic1" #define GATT_DESCRIPTOR_IFACE "org.bluez.GattDescriptor1" -#define EATT_MAX_BEARERS 2 - struct btd_gatt_client { struct btd_device *device; uint8_t features; @@ -2171,6 +2169,7 @@ static void eatt_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data) static void eatt_connect(struct btd_gatt_client *client) { + struct bt_att *att = bt_gatt_client_get_att(client->gatt); struct btd_device *dev = client->device; struct btd_adapter *adapter = device_get_adapter(dev); GIOChannel *io; @@ -2178,11 +2177,14 @@ static void eatt_connect(struct btd_gatt_client *client) char addr[18]; int i; + if (bt_att_get_channels(att) == main_opts.gatt_channels) + return; + ba2str(device_get_address(dev), addr); DBG("Connection attempt to: %s", addr); - for (i = 0; i < EATT_MAX_BEARERS; i++) { + for (i = bt_att_get_channels(att); i < main_opts.gatt_channels; i++) { io = bt_io_connect(eatt_connect_cb, client, NULL, NULL, BT_IO_OPT_SOURCE_BDADDR, btd_adapter_get_address(adapter), diff --git a/src/gatt-database.c b/src/gatt-database.c index 1b514aa4f..d0ab4da99 100644 --- a/src/gatt-database.c +++ b/src/gatt-database.c @@ -1215,10 +1215,13 @@ static void populate_gatt_service(struct btd_gatt_database *database) &uuid, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ, db_hash_read_cb, NULL, database); - bt_uuid16_create(&uuid, GATT_CHARAC_SERVER_FEAT); - database->eatt = gatt_db_service_add_characteristic(service, + /* Only enable EATT if there is a socket listening */ + if (database->eatt_io) { + bt_uuid16_create(&uuid, GATT_CHARAC_SERVER_FEAT); + database->eatt = gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ, server_feat_read_cb, NULL, database); + } gatt_db_service_set_active(service, true); @@ -3564,6 +3567,10 @@ struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter) goto fail; } + /* If just just 1 channel is enabled EATT is not required */ + if (main_opts.gatt_channels == 1) + goto bredr; + /* EATT socket */ database->eatt_io = bt_io_listen(connect_cb, NULL, NULL, NULL, NULL, BT_IO_OPT_SOURCE_BDADDR, addr, @@ -3591,6 +3598,7 @@ struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter) } } +bredr: /* BR/EDR socket */ database->bredr_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, addr, diff --git a/src/hcid.h b/src/hcid.h index ca405fde4..1bf93784d 100644 --- a/src/hcid.h +++ b/src/hcid.h @@ -62,6 +62,7 @@ struct main_opts { bt_mode_t mode; bt_gatt_cache_t gatt_cache; uint16_t gatt_mtu; + uint8_t gatt_channels; uint8_t key_size; diff --git a/src/main.c b/src/main.c index fc8c869fc..7b927ac79 100644 --- a/src/main.c +++ b/src/main.c @@ -109,6 +109,7 @@ static const char *gatt_options[] = { "Cache", "KeySize", "ExchangeMTU", + "EATTChannels", NULL }; @@ -471,6 +472,18 @@ static void parse_config(GKeyFile *config) DBG("ExchangeMTU=%d", val); main_opts.gatt_mtu = val; } + + val = g_key_file_get_integer(config, "GATT", "Channels", &err); + if (err) { + DBG("%s", err->message); + g_clear_error(&err); + } else { + DBG("Channels=%d", val); + /* Ensure the channels is within a valid range. */ + val = MIN(val, 5); + val = MAX(val, 1); + main_opts.gatt_channels = val; + } } static void init_defaults(void) @@ -497,6 +510,7 @@ static void init_defaults(void) main_opts.gatt_cache = BT_GATT_CACHE_ALWAYS; main_opts.gatt_mtu = BT_ATT_MAX_LE_MTU; + main_opts.gatt_channels = 3; } static void log_handler(const gchar *log_domain, GLogLevelFlags log_level, diff --git a/src/main.conf b/src/main.conf index bb5ff5b15..16701ebe4 100644 --- a/src/main.conf +++ b/src/main.conf @@ -99,6 +99,11 @@ # Defaults to 517 #ExchangeMTU = 517 +# Number of ATT channels +# Possible values: 1-5 (1 disables EATT) +# Default to 3 +#Channels = 3 + [Policy] # # The ReconnectUUIDs defines the set of remote services that should try From patchwork Fri Feb 28 23:47:01 2020 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: 197327 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.0 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 06387C3F2CD for ; Fri, 28 Feb 2020 23:47:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D0409246B9 for ; Fri, 28 Feb 2020 23:47:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BomLSKbx" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726589AbgB1XrS (ORCPT ); Fri, 28 Feb 2020 18:47:18 -0500 Received: from mail-pg1-f194.google.com ([209.85.215.194]:39197 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726859AbgB1XrS (ORCPT ); Fri, 28 Feb 2020 18:47:18 -0500 Received: by mail-pg1-f194.google.com with SMTP id s2so1438852pgv.6 for ; Fri, 28 Feb 2020 15:47:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=Ihpr9Y1VTzQzgPw9VEZXNNYIhYzl+fh8ZyruBbafTqs=; b=BomLSKbxqm14l62RVdci9cGy5/vAT/By4PN2LjJaYz6s6lm2yhB3U10E8fqfTgkg29 mB2vT0dPdnqg5TC+C3EXfiPT3ER1OJERjub5x8iBt4NLtEfZ7qYKcEzJq0S1VCNeAPUP ire4Eq99v9QqFSjffMUYjUrr73p4F3bqrxy5omdrcBTxeNCBVw1Kd5mlVsJWscEEThjO uBNqDy68mumYqaY5k4tlIjQtrzkiiH0/ryT5z3hxntEftCFPc31ecMWgWb8uq4GkI6oT vJLYGgToXxKHBvOM3rTwtV3LInUyB/z3R2of7WfpyaNUdIT+x9zJiYHvX5ordLdYXtWq WceA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Ihpr9Y1VTzQzgPw9VEZXNNYIhYzl+fh8ZyruBbafTqs=; b=aBVFvNMsd7Hncqwjsyfk2BVUJFxpyPe2oCuYknxcikBpcz+/tES5B7XwJp/8r9FN6R BbncSuFz4uVCM50vgVUL2ccGWYmRtoZ3YoLjqT2rXm7D/cKfifm+bJe6T4+Jlv79yBNV 98NwLT1pFl6zo4xxpPXtt4q11Rp5oPKVx2KP2eCzTQsso1mzwwZ71AYp4WgB/vUrCiZB LJoX72IuTXp37G8wyulsTyMni+5N7mZqJhdoncbm0aVySCKtHTE/kybrb7jAAyZj2ZMl 4l9atD76iP2pJfV3L0l0IsQ6sYk20LpyooNp6S1PLF1sYC9mlwLCk/FWIGRTRUhBq6Rj PzFA== X-Gm-Message-State: APjAAAWQbG2ODstB2r2jnhJkhN4iWkSdLgaZynstnbpo47VRyJlh9TPg sUKt+f30A8kBadRxrh/A5KFF2c7nHqI= X-Google-Smtp-Source: APXvYqyW3v57MPE2tPOo3vYqBeHnxM5MQSErh4bz4Wa62RLiXiq+jeJ93cy9oafsSBTQagqoc8389w== X-Received: by 2002:a63:6cc6:: with SMTP id h189mr6781156pgc.201.1582933636601; Fri, 28 Feb 2020 15:47:16 -0800 (PST) Received: from localhost.localdomain (c-71-56-157-77.hsd1.or.comcast.net. [71.56.157.77]) by smtp.gmail.com with ESMTPSA id q13sm13643954pfn.162.2020.02.28.15.47.15 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2020 15:47:15 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH v2 12/12] monitor: Add support for decoding EATT Date: Fri, 28 Feb 2020 15:47:01 -0800 Message-Id: <20200228234701.14614-13-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200228234701.14614-1-luiz.dentz@gmail.com> References: <20200228234701.14614-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz This decodes packets received over EATT PSM. --- monitor/l2cap.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/monitor/l2cap.c b/monitor/l2cap.c index 3b2b25f24..9409604c3 100644 --- a/monitor/l2cap.c +++ b/monitor/l2cap.c @@ -2573,6 +2573,36 @@ static void att_handle_value_conf(const struct l2cap_frame *frame) { } +static void att_multiple_vl_rsp(const struct l2cap_frame *frame) +{ + struct l2cap_frame *f = (void *) frame; + + while (frame->size) { + uint16_t handle; + uint16_t len; + + if (!l2cap_frame_get_le16(f, &handle)) + return; + + print_field("Handle: 0x%4.4x", handle); + + if (!l2cap_frame_get_le16(f, &len)) + return; + + print_field("Length: 0x%4.4x", len); + + print_hex_field(" Data", f->data, + len < f->size ? len : f->size); + + if (len > f->size) { + print_text(COLOR_ERROR, "invalid size"); + return; + } + + l2cap_frame_pull(f, f, len); + } +} + static void att_write_command(const struct l2cap_frame *frame) { print_field("Handle: 0x%4.4x", get_le16(frame->data)); @@ -2645,6 +2675,12 @@ static const struct att_opcode_data att_opcode_table[] = { att_handle_value_ind, 2, false }, { 0x1e, "Handle Value Confirmation", att_handle_value_conf, 0, true }, + { 0x20, "Read Multiple Request Variable Length", + att_read_multiple_req, 4, false }, + { 0x21, "Read Multiple Response Variable Length", + att_multiple_vl_rsp, 4, false }, + { 0x23, "Handle Multiple Value Notification", + att_multiple_vl_rsp, 4, false }, { 0x52, "Write Command", att_write_command, 2, false }, { 0xd2, "Signed Write Command", att_signed_write_command, 14, false }, @@ -3287,6 +3323,9 @@ void l2cap_frame(uint16_t index, bool in, uint16_t handle, uint16_t cid, case 0x001f: att_packet(index, in, handle, cid, data, size); break; + case 0x0027: + att_packet(index, in, handle, cid, data + 2, size - 2); + break; case 0x0017: case 0x001B: avctp_packet(&frame);