From patchwork Thu Feb 24 02:06:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Gix X-Patchwork-Id: 12757782 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 51DE9C433F5 for ; Thu, 24 Feb 2022 02:06:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229940AbiBXCHG (ORCPT ); Wed, 23 Feb 2022 21:07:06 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53738 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229901AbiBXCHF (ORCPT ); Wed, 23 Feb 2022 21:07:05 -0500 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 27AD6641D for ; Wed, 23 Feb 2022 18:06:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645668395; x=1677204395; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Cvd+xLakMB/8GSTNTyEuvAKnMwdMeGT9MJgKOHxAYGg=; b=IRKppubHz6mawX+4bLwv0SAxpbLWri+0EAROLi+6fVeLdjPFOqirldgf p/wCt0ZXODb7uInbWDKleL9Jl9VnDENB3oyhYQiPkT7/Vjw/UUZ/J1YcE Zh4wR/sfEoBsju8FfJ0CNY5aTTE8c0bm/DY7Dm8IonCtkTjavRL9DAZXy jIzuJy5zgRCd8Sw7RXkrnMwQ4Wv0LL1AWd5WZQJ24F1S5QUUKRrUXXnuI xCZKS2hnPNcQfE/MTNAR8+ZCj6ce+GZdea8/gBaldPUADeBoljqwqeZ19 B9bPIAgjqe5XKb/nIH4LH+BOzjoea8dySKhNUBJ7ouHBc0mwMyHeHDS4a A==; X-IronPort-AV: E=McAfee;i="6200,9189,10267"; a="239524996" X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="239524996" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:33 -0800 X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="607268562" Received: from tjsmith-mobl1.amr.corp.intel.com (HELO bgi1-mobl2.amr.corp.intel.com) ([10.209.34.213]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:33 -0800 From: Brian Gix To: linux-bluetooth@vger.kernel.org Cc: brian.gix@intel.com, inga.stotland@intel.com Subject: [PATCH 1/7] mgmt: Add support for Mesh in the kernel Date: Wed, 23 Feb 2022 18:06:18 -0800 Message-Id: <20220224020624.159247-2-brian.gix@intel.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220224020624.159247-1-brian.gix@intel.com> References: <20220224020624.159247-1-brian.gix@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org These commands and events allow User space apps to test for Mesh support, and request incoming mesh packets be delivered and request outbound mesh packets to be sent. This is the basis for sharing one controller between the legacy bluetoothd daemon and the mesh bluetooth-meshd daemon. --- doc/mgmt-api.txt | 180 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt index ebe56afa4..41c196250 100644 --- a/doc/mgmt-api.txt +++ b/doc/mgmt-api.txt @@ -3858,6 +3858,132 @@ Add Advertisement Patterns Monitor With RSSI Threshold Command Invalid Parameters +Set Mesh Receiver Command +========================= + + Command Code: 0x0057 + Controller Index: + Command Parameters: Enable (1 Octets) + Window (2 Octets) + Period (2 Octets) + Num AD Types (1 Octets) + AD Types { } + + This command Enables or Disables Mesh Receiving. When enabled passive + scanning remains enabled for this controller. + + The Window/Period values are used to set the Scan Parameters when no + other scanning is being done. + + Num AD Types and AD Types parameter, filter Advertising and Scan + responses by AD type. Reponses that do not contain at least one of the + requested AD types will be ignored. Otherwise they will be delivered + with the Mesh Device Found event. + + Possible errors: Failed + No Resources + Invalid Parameters + + +Read Mesh Features Command +========================== + + Command Code: 0x0058 + Controller Index: + Command Parameters: + Return Parameters: Index (2 Octets) + Max Handles (1 Octets) + Used Handles (1 Octets) + Handle { } + + This command is used to both verify that Outbound Mesh packet + support is enabled, and to indicate the number of packets that + can and are simultaneously queued. + + Index identifies the HCI Controller that this information is valid for. + + Max Handles indicates the maximum number of packets that may be queued. + + Used Handles indicates the number of packets awaiting transmission. + + Handle is an array of the currently outstanding packets. + + Possible errors: Failed + No Resources + Invalid Parameters + + +Transmit Mesh Packet Command +============================ + + Command Code: 0x0059 + Controller Index: + Command Parameters: Addr (6 octets) + Addr Type (1 Octets) + Instant (8 Octets) + Delay (2 Octets) + Count (1 Octets) + Data (variable) + + Return Parameters: Handle (1 Octets) + + This command sends a Mesh Packet as a NONCONN LE Advertisement. + + The Addr + Addr Type parameters specifify the address to use in the + outbound advertising packet. If BD_ADDR_ANY and LE_RANDOM is set, the + kernel will create a single use non-resolvable address. + + The Instant parameter is used in combination with the Delay + parameter, to finely time the sending of the Advertising packet. It + should be set to the Instant value tag of a received incoming + Mesh Device Found Event. It is only useful in POLL-RESPONSE situations + where a response must be sent within a negotiated time window. The value + of the Instant parameter should not be interpreted by the host, and + only has meaning to the controller. + + The Delay parameter, if 0x0000, will cause the packet to be sent + at the earliest opportunity. If non-Zero, and the controller supports + delayed delivery, the Instant and Delay parameters will be used + to delay the outbound packet. While the Instant is not defined, the + Delay is specified in milliseconds. + + The Count parameter must be sent to a non-Zero value indicating the + number of times this packet will be sent before transmission completes. + If the Delay parameter is non-Zero, then Count must be 1 only. + + The Data parameter is an octet array of the AD Type and Mesh Packet. + + This command will return immediately, and if it succeeds, will generate + a Mesh Packet Transmission Complete event when after the packet has been + sent. + + Possible errors: Failed + Busy + No Resources + Invalid Parameters + + +Cancel Transmit Mesh Packet Command +=================================== + + Command Code: 0x005A + Controller Index: + Command Parameters: Handle (1 Octets) + + This command may be used to cancel an outbound transmission request. + + The Handle parameter is the returned handle from a successful Transmit + Mesh Packet request. If Zero is specified as the handle, all outstanding + send requests are canceled. + + For each mesh packet canceled, the Mesh Packet Transmission Complete + event will be generated, regardless of whether the packet was sent + successfully. + + Possible errors: Failed + Invalid Parameters + + Command Complete Event ====================== @@ -4978,3 +5104,57 @@ Advertisement Monitor Device Lost Event 2 LE Random This event will be sent to all management sockets. + + +Mesh Device Found Event +======================= + + Event code: 0x0031 + Controller Index: + Event Parameters: Address (6 Octets) + Address_Type (1 Octet) + RSSI (1 Octet) + Flags (4 Octets) + Instant (8 Octets) + AD_Data_Length (2 Octets) + AD_Data (0-65535 Octets) + + This event indicates that the controller has received an Advertisement + or Scan Result containing an AD Type matching the Mesh scan set. + + The address of the sending device is returned, and must be a valid LE + Address_Type. + + Possible values for the Address_Type parameter: + 0 Reserved (not in use) + 1 LE Public + 2 LE Random + + The RSSI field is a signed octet, and is the RSSI reported by the + receiving controller. + + The Instant field is 64 bit value that represents the instant in time + the packet was received. It's value is not intended to be interpretted + by the host, and is only useful if the host wants to make a timed + response to the received packet. (i.e. a Poll/Response) + + AD_Length and AD_Data contains the Info structure of Advertising and + Scan rsults. To receive this event, AD filters must be requested with + the Set Mesh Receiver command command, specifying which AD Types to + return. All AD structures will be received in this event if any of the + filtered AD Types are present. + + This event will be sent to all management sockets. + + +Mesh Packet Transmit Complete Event +=================================== + + Event code: 0x0032 + Controller Index: + Event Parameters: Handle (1 Octets) + + This event indicates that a requested outbound Mesh packet has + completed and no longer occupies a transmit slot. + + This event will be sent to all management sockets. From patchwork Thu Feb 24 02:06:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Gix X-Patchwork-Id: 12757781 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 DF916C433EF for ; Thu, 24 Feb 2022 02:06:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229939AbiBXCHG (ORCPT ); Wed, 23 Feb 2022 21:07:06 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53740 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229934AbiBXCHF (ORCPT ); Wed, 23 Feb 2022 21:07:05 -0500 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5979DB7C0 for ; Wed, 23 Feb 2022 18:06:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645668395; x=1677204395; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=KWtoRVa6DUZj876vQchwt43T6iq/a2fHQVwOF3bGLiw=; b=fJpzEp4/ztDKknw1BWM7O9ByZEeWMKIywVLlsI2HpQDrMRlqLiHGVIIR GbQGlOrdr14hzE4pER4w5zhQWrPXpcvdwymzFxNJLeYWx6o3EZ1HhzHdp pIhr+8/IBhQk7YFEztXRGV1xjka+NHSQcbb52/Es5pXFh0DDvu+TAuk2k g8U/lC6cOKKMimfamdgiT8pUr7QxJq+NRa4ubdktPTA12UhH75BTYOSBq zYGI4FKDRXozUzQX1s57s6qnsEuIUB9iXSnsJQAKDkErx4FYSoqeI2M5G rT9WWK7NIAfDs6+JY24nlM5FkbpZFY3E7Yzl/ce9mGcuo8owvG2dkRkun A==; X-IronPort-AV: E=McAfee;i="6200,9189,10267"; a="239524999" X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="239524999" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:33 -0800 X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="607268565" Received: from tjsmith-mobl1.amr.corp.intel.com (HELO bgi1-mobl2.amr.corp.intel.com) ([10.209.34.213]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:33 -0800 From: Brian Gix To: linux-bluetooth@vger.kernel.org Cc: brian.gix@intel.com, inga.stotland@intel.com Subject: [PATCH 2/7] mgmt: Mesh specific structures and defines Date: Wed, 23 Feb 2022 18:06:19 -0800 Message-Id: <20220224020624.159247-3-brian.gix@intel.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220224020624.159247-1-brian.gix@intel.com> References: <20220224020624.159247-1-brian.gix@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org Adds the Mesh commands and events as described in mgmt-api.txt --- lib/mgmt.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/lib/mgmt.h b/lib/mgmt.h index 922a24367..d5ec58228 100644 --- a/lib/mgmt.h +++ b/lib/mgmt.h @@ -757,6 +757,39 @@ struct mgmt_cp_add_adv_patterns_monitor_rssi { struct mgmt_adv_pattern patterns[0]; } __packed; +#define MGMT_OP_SET_MESH_RECEIVER 0x0057 +struct mgmt_cp_set_mesh { + uint8_t enable; + uint16_t window; + uint16_t period; + uint8_t num_ad_types; + uint8_t ad_types[]; +} __packed; + +#define MGMT_OP_MESH_READ_FEATURES 0x0058 +struct mgmt_rp_mesh_read_features { + uint16_t index; + uint8_t max_handles; + uint8_t used_handles; + uint8_t handles[]; +} __packed; + + +#define MGMT_OP_MESH_SEND 0x0059 +struct mgmt_cp_mesh_send { + struct mgmt_addr_info addr; + uint64_t instant; + uint16_t delay; + uint8_t cnt; + uint8_t data[]; +} __packed; + +#define MGMT_OP_MESH_SEND_CANCEL 0x005A +struct mgmt_cp_mesh_send_cancel { + uint8_t handle; +} __packed; + + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { uint16_t opcode; @@ -1032,6 +1065,21 @@ struct mgmt_ev_adv_monitor_device_lost { struct mgmt_addr_info addr; } __packed; +#define MGMT_EV_MESH_DEVICE_FOUND 0x0031 +struct mgmt_ev_mesh_device_found { + struct mgmt_addr_info addr; + int8_t rssi; + uint32_t flags; + uint64_t instant; + uint16_t eir_len; + uint8_t eir[]; +} __packed; + +#define MGMT_EV_MESH_PACKET_CMPLT 0x0032 +struct mgmt_ev_mesh_pkt_cmplt { + uint8_t handle; +} __packed; + static const char *mgmt_op[] = { "<0x0000>", "Read Version", @@ -1120,6 +1168,10 @@ static const char *mgmt_op[] = { "Add Extended Advertisement Parameters", /* 0x0054 */ "Add Extended Advertisement Data", "Add Advertisement Patterns Monitor RSSI", + "Set Mesh Receiver", + "Read Mesh Features", + "Mesh Send", + "Mesh Send Cancel", }; static const char *mgmt_ev[] = { @@ -1172,6 +1224,8 @@ static const char *mgmt_ev[] = { "Controller Resume", "Advertisement Monitor Device Found", /* 0x002f */ "Advertisement Monitor Device Lost", + "Mesh Packet Found", + "Mesh Packet Complete", }; static const char *mgmt_status[] = { From patchwork Thu Feb 24 02:06:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Gix X-Patchwork-Id: 12757783 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 C679BC433F5 for ; Thu, 24 Feb 2022 02:06:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229952AbiBXCHI (ORCPT ); Wed, 23 Feb 2022 21:07:08 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53860 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229941AbiBXCHH (ORCPT ); Wed, 23 Feb 2022 21:07:07 -0500 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 51E1DB853 for ; Wed, 23 Feb 2022 18:06:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645668397; x=1677204397; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=81ea5c0d54wLGPgGbtraKs9AyWMBNQkSxgLGbaTQ3bQ=; b=OL4hSSq9wDzpyX9v5xNwW2XeVsp0iRIh+Mnx+WWWES+MZt0O6s9n/Qdg znpWlSSNqE5hEFHaYHgZtWsLRSwZqZ7hKovjfeEw9kDP+9Q+XgNNXMqVV +Db2r7Jr6TVo6XXQBM+cusrgH/s47NoujM8efwrf1tagSNGXtJOnHj7gW PaCuuI1fSIuz6et3RfdCUdmXGyXhSj7n0oGKy9LUmaw2tpByQz9jQA7Vg XEtZxw+xwRftnjILX+J49oWPiXx324alB+NRIMJfMpr4Sg+JqlMUZPwi4 R0n6A5GXDRYM1mk2d7i/ytGhTmKT/md7x49Hw4Z9Qjv2Up6DePdmP70Ya A==; X-IronPort-AV: E=McAfee;i="6200,9189,10267"; a="239525000" X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="239525000" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:33 -0800 X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="607268568" Received: from tjsmith-mobl1.amr.corp.intel.com (HELO bgi1-mobl2.amr.corp.intel.com) ([10.209.34.213]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:33 -0800 From: Brian Gix To: linux-bluetooth@vger.kernel.org Cc: brian.gix@intel.com, inga.stotland@intel.com Subject: [PATCH 3/7] mesh: Add common MGMT command accessors Date: Wed, 23 Feb 2022 18:06:20 -0800 Message-Id: <20220224020624.159247-4-brian.gix@intel.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220224020624.159247-1-brian.gix@intel.com> References: <20220224020624.159247-1-brian.gix@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org While mesh-io-mgmt is the main consumer of MGMT services, we also use MGMT to identify controllers and their capabilities, when determining the appropriate Mesh IO carrier. This centralizes all MGMT access to a single socket, shared accross all consumers. Also fixes the Controller added/removed handling so that a controller disappearing or reappearing gets handled rationally. --- mesh/mesh-mgmt.c | 149 ++++++++++++++++++++++++++++++++++++----------- mesh/mesh-mgmt.h | 12 +++- 2 files changed, 125 insertions(+), 36 deletions(-) diff --git a/mesh/mesh-mgmt.c b/mesh/mesh-mgmt.c index 754093dbc..e878a4f11 100644 --- a/mesh/mesh-mgmt.c +++ b/mesh/mesh-mgmt.c @@ -12,35 +12,63 @@ #include #endif +#include + #include "lib/bluetooth.h" #include "lib/mgmt.h" #include "src/shared/mgmt.h" -#include "ell/queue.h" -#include "ell/log.h" -#include "ell/util.h" - #include "mesh/mesh-mgmt.h" -struct read_info_reg { - mesh_mgmt_read_info_func_t cb; - void *user_data; -}; - -struct read_info_req { - int index; - struct mesh_io *io; +struct mesh_controler { + int index; + bool mesh_support; + bool powered; }; +static mesh_mgmt_read_info_func_t ctl_info; static struct mgmt *mgmt_mesh; -static struct l_queue *read_info_regs; +static struct l_queue *ctl_list; +static void *list_user_data; +static bool mesh_detected; + +static bool by_index(const void *a, const void *b) +{ + const struct mesh_controler *ctl = a; + int index = L_PTR_TO_UINT(b); -static void process_read_info_req(void *data, void *user_data) + return ctl->index == index; +} + +static void index_removed(uint16_t index, uint16_t length, const void *param, + void *user_data); +static void features_cb(uint8_t status, uint16_t length, + const void *param, void *user_data) { - struct read_info_reg *reg = data; int index = L_PTR_TO_UINT(user_data); + struct mesh_controler *ctl; + - reg->cb(index, reg->user_data); + ctl = l_queue_find(ctl_list, by_index, L_UINT_TO_PTR(index)); + if (!ctl) + return; + + l_debug("Status: %d, Length: %d", status, length); + if (status != MGMT_STATUS_NOT_SUPPORTED && + status != MGMT_STATUS_UNKNOWN_COMMAND) { + ctl->mesh_support = true; + if (!mesh_detected) { + mgmt_register(mgmt_mesh, MGMT_EV_INDEX_REMOVED, + MGMT_INDEX_NONE, index_removed, + NULL, NULL); + } + mesh_detected = true; + } else + l_debug("Kernel mesh not supported for hci%u", index); + + if (ctl_info) + ctl_info(index, true, ctl->powered, ctl->mesh_support, + list_user_data); } static void read_info_cb(uint8_t status, uint16_t length, @@ -49,12 +77,25 @@ static void read_info_cb(uint8_t status, uint16_t length, int index = L_PTR_TO_UINT(user_data); const struct mgmt_rp_read_info *rp = param; uint32_t current_settings, supported_settings; + struct mesh_controler *ctl; l_debug("hci %u status 0x%02x", index, status); + ctl = l_queue_find(ctl_list, by_index, L_UINT_TO_PTR(index)); + if (!ctl) + return; + if (status != MGMT_STATUS_SUCCESS) { + ctl = l_queue_remove_if(ctl_list, by_index, + L_UINT_TO_PTR(index)); l_error("Failed to read info for hci index %u: %s (0x%02x)", index, mgmt_errstr(status), status); + + l_warn("Hci dev %d removal detected", index); + if (ctl && ctl_info) + ctl_info(index, false, false, false, list_user_data); + + l_free(ctl); return; } @@ -69,23 +110,34 @@ static void read_info_cb(uint8_t status, uint16_t length, l_debug("settings: supp %8.8x curr %8.8x", supported_settings, current_settings); - if (current_settings & MGMT_SETTING_POWERED) { - l_info("Controller hci %u is in use", index); - return; - } - if (!(supported_settings & MGMT_SETTING_LE)) { l_info("Controller hci %u does not support LE", index); + l_queue_remove(ctl_list, ctl); + l_free(ctl); return; } - l_queue_foreach(read_info_regs, process_read_info_req, - L_UINT_TO_PTR(index)); + if (current_settings & MGMT_SETTING_POWERED) + ctl->powered = true; + + mesh_mgmt_send(MGMT_OP_MESH_READ_FEATURES, index, 0, NULL, + features_cb, L_UINT_TO_PTR(index), NULL); } static void index_added(uint16_t index, uint16_t length, const void *param, void *user_data) { + struct mesh_controler *ctl = l_queue_find(ctl_list, by_index, + L_UINT_TO_PTR(index)); + + if (!ctl) { + ctl = l_new(struct mesh_controler, 1); + ctl->index = index; + l_queue_push_head(ctl_list, ctl); + } else { + ctl->mesh_support = ctl->powered = false; + } + mgmt_send(mgmt_mesh, MGMT_OP_READ_INFO, index, 0, NULL, read_info_cb, L_UINT_TO_PTR(index), NULL); } @@ -93,7 +145,9 @@ static void index_added(uint16_t index, uint16_t length, const void *param, static void index_removed(uint16_t index, uint16_t length, const void *param, void *user_data) { - l_warn("Hci dev %4.4x removed", index); + mgmt_send(mgmt_mesh, MGMT_OP_READ_INFO, index, 0, NULL, + read_info_cb, L_UINT_TO_PTR(index), NULL); + } static void read_index_list_cb(uint8_t status, uint16_t length, @@ -133,8 +187,8 @@ static void read_index_list_cb(uint8_t status, uint16_t length, static bool mesh_mgmt_init(void) { - if (!read_info_regs) - read_info_regs = l_queue_new(); + if (!ctl_list) + ctl_list = l_queue_new(); if (!mgmt_mesh) { mgmt_mesh = mgmt_new_default(); @@ -146,8 +200,6 @@ static bool mesh_mgmt_init(void) mgmt_register(mgmt_mesh, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE, index_added, NULL, NULL); - mgmt_register(mgmt_mesh, MGMT_EV_INDEX_REMOVED, - MGMT_INDEX_NONE, index_removed, NULL, NULL); } return true; @@ -155,16 +207,11 @@ static bool mesh_mgmt_init(void) bool mesh_mgmt_list(mesh_mgmt_read_info_func_t cb, void *user_data) { - struct read_info_reg *reg; - if (!mesh_mgmt_init()) return false; - reg = l_new(struct read_info_reg, 1); - reg->cb = cb; - reg->user_data = user_data; - - l_queue_push_tail(read_info_regs, reg); + ctl_info = cb; + list_user_data = user_data; /* Use MGMT to find a candidate controller */ l_debug("send read index_list"); @@ -175,3 +222,35 @@ bool mesh_mgmt_list(mesh_mgmt_read_info_func_t cb, void *user_data) return true; } + +void mesh_mgmt_destroy() +{ + mgmt_unref(mgmt_mesh); + mgmt_mesh = NULL; + ctl_info = NULL; + list_user_data = NULL; + l_queue_destroy(ctl_list, l_free); + ctl_list = NULL; +} + +unsigned int mesh_mgmt_send(uint16_t opcode, uint16_t index, + uint16_t length, const void *param, + mgmt_request_func_t callback, + void *user_data, mgmt_destroy_func_t destroy) +{ + return mgmt_send_timeout(mgmt_mesh, opcode, index, length, param, + callback, user_data, destroy, 0); +} + +unsigned int mesh_mgmt_register(uint16_t event, uint16_t index, + mgmt_notify_func_t callback, + void *user_data, mgmt_destroy_func_t destroy) +{ + return mgmt_register(mgmt_mesh, event, index, callback, + user_data, destroy); +} + +bool mesh_mgmt_unregister(unsigned int id) +{ + return mgmt_unregister(mgmt_mesh, id); +} diff --git a/mesh/mesh-mgmt.h b/mesh/mesh-mgmt.h index 90ac14e73..a3cd72faf 100644 --- a/mesh/mesh-mgmt.h +++ b/mesh/mesh-mgmt.h @@ -9,6 +9,16 @@ */ #include -typedef void (*mesh_mgmt_read_info_func_t)(int index, void *user_data); +typedef void (*mesh_mgmt_read_info_func_t)(int index, bool added, bool powered, + bool mesh, void *user_data); bool mesh_mgmt_list(mesh_mgmt_read_info_func_t cb, void *user_data); +unsigned int mesh_mgmt_send(uint16_t opcode, uint16_t index, + uint16_t length, const void *param, + mgmt_request_func_t callback, + void *user_data, mgmt_destroy_func_t destroy); +unsigned int mesh_mgmt_register(uint16_t event, uint16_t index, + mgmt_notify_func_t callback, + void *user_data, mgmt_destroy_func_t destroy); +bool mesh_mgmt_unregister(unsigned int id); +void mesh_mgmt_destroy(void); From patchwork Thu Feb 24 02:06:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Gix X-Patchwork-Id: 12757784 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 4BA42C433EF for ; Thu, 24 Feb 2022 02:06:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229962AbiBXCHJ (ORCPT ); Wed, 23 Feb 2022 21:07:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53884 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229944AbiBXCHH (ORCPT ); Wed, 23 Feb 2022 21:07:07 -0500 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 520E7BC14 for ; Wed, 23 Feb 2022 18:06:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645668397; x=1677204397; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bM+/ZuEyWOEFwP74CBNA/J/qR51WuKedqkohDaDW36M=; b=UVvwTAhu8FM5KZ++u09cq9StKjsc2wY6V7icoyvrwz2xc08fXa46qYnM iI+ADfIzvlxNE/rsQ9b/jVOGYyRgeNaKixgaSOnEScLlYzwLWCGAbb2Fa Phh65M6M+rA9G3OAfnNei/qoCv+ij3MEaR2TL/4DgTd6x0WeuPCTOzNVj LfNJjxCLtUjnow2cOExMWVIlPk+I2jbYq0VLjY1JiMeBVsjfIMRU4j/Vw Du7OFfLDBOQ66+f3f4R7XafYHLH/V30hwB2kZdCIT7hWh+rCfOua2vLET KSQvalUYcHlOUCYsltddQFsfoyPCZqbmdagFG+kHSXDVFNwD48voI8Rmh Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10267"; a="239525002" X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="239525002" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:34 -0800 X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="607268572" Received: from tjsmith-mobl1.amr.corp.intel.com (HELO bgi1-mobl2.amr.corp.intel.com) ([10.209.34.213]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:34 -0800 From: Brian Gix To: linux-bluetooth@vger.kernel.org Cc: brian.gix@intel.com, inga.stotland@intel.com Subject: [PATCH 4/7] mesh: rework Mesh-IO for multiple transports Date: Wed, 23 Feb 2022 18:06:21 -0800 Message-Id: <20220224020624.159247-5-brian.gix@intel.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220224020624.159247-1-brian.gix@intel.com> References: <20220224020624.159247-1-brian.gix@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org This patch adds mesh-io-mgmt (Kernel MGMT based transport) and streamlines the handling of identifying and activating the appropriate transport. --- mesh/mesh-io-api.h | 11 +- mesh/mesh-io-generic.c | 47 +-- mesh/mesh-io-generic.h | 1 + mesh/mesh-io-mgmt.c | 787 +++++++++++++++++++++++++++++++++++++++++ mesh/mesh-io-unit.c | 11 +- mesh/mesh-io.c | 190 +++++++--- mesh/mesh-io.h | 4 +- 7 files changed, 957 insertions(+), 94 deletions(-) create mode 100644 mesh/mesh-io-mgmt.c diff --git a/mesh/mesh-io-api.h b/mesh/mesh-io-api.h index 61f79f224..21c505cd0 100644 --- a/mesh/mesh-io-api.h +++ b/mesh/mesh-io-api.h @@ -10,8 +10,7 @@ struct mesh_io_private; -typedef bool (*mesh_io_init_t)(struct mesh_io *io, void *opts, - mesh_io_ready_func_t cb, void *user_data); +typedef bool (*mesh_io_init_t)(struct mesh_io *io, void *opts, void *user_data); typedef bool (*mesh_io_destroy_t)(struct mesh_io *io); typedef bool (*mesh_io_caps_t)(struct mesh_io *io, struct mesh_io_caps *caps); typedef bool (*mesh_io_send_t)(struct mesh_io *io, @@ -36,9 +35,13 @@ struct mesh_io_api { }; struct mesh_io { - enum mesh_io_type type; - const struct mesh_io_api *api; + int index; + int favored_index; + mesh_io_ready_func_t ready; + struct l_queue *rx_regs; struct mesh_io_private *pvt; + void *user_data; + const struct mesh_io_api *api; }; struct mesh_io_table { diff --git a/mesh/mesh-io-generic.c b/mesh/mesh-io-generic.c index 6c0b8f0fd..0bf8fcd81 100644 --- a/mesh/mesh-io-generic.c +++ b/mesh/mesh-io-generic.c @@ -19,6 +19,7 @@ #include "monitor/bt.h" #include "src/shared/hci.h" +#include "src/shared/mgmt.h" #include "lib/bluetooth.h" #include "lib/mgmt.h" @@ -29,14 +30,12 @@ #include "mesh/mesh-io-generic.h" struct mesh_io_private { + struct mesh_io *io; struct bt_hci *hci; - void *user_data; - mesh_io_ready_func_t ready_callback; struct l_timeout *tx_timeout; struct l_queue *rx_regs; struct l_queue *tx_pkts; struct tx_pkt *tx; - uint16_t index; uint16_t interval; bool sending; bool active; @@ -385,16 +384,13 @@ static void hci_init(void *user_data) { struct mesh_io *io = user_data; bool result = true; - bool restarted = false; - if (io->pvt->hci) { - restarted = true; + if (io->pvt->hci) bt_hci_unref(io->pvt->hci); - } - io->pvt->hci = bt_hci_new_user_channel(io->pvt->index); + io->pvt->hci = bt_hci_new_user_channel(io->index); if (!io->pvt->hci) { - l_error("Failed to start mesh io (hci %u): %s", io->pvt->index, + l_error("Failed to start mesh io (hci %u): %s", io->index, strerror(errno)); result = false; } @@ -405,47 +401,26 @@ static void hci_init(void *user_data) bt_hci_register(io->pvt->hci, BT_HCI_EVT_LE_META_EVENT, event_callback, io, NULL); - l_debug("Started mesh on hci %u", io->pvt->index); + l_debug("Started mesh on hci %u", io->index); - if (restarted) - restart_scan(io->pvt); + restart_scan(io->pvt); } - if (io->pvt->ready_callback) - io->pvt->ready_callback(io->pvt->user_data, result); + if (io->ready) + io->ready(io->user_data, result); } -static void read_info(int index, void *user_data) -{ - struct mesh_io *io = user_data; - - if (io->pvt->index != MGMT_INDEX_NONE && - index != io->pvt->index) { - l_debug("Ignore index %d", index); - return; - } - - io->pvt->index = index; - hci_init(io); -} - -static bool dev_init(struct mesh_io *io, void *opts, - mesh_io_ready_func_t cb, void *user_data) +static bool dev_init(struct mesh_io *io, void *opts, void *user_data) { if (!io || io->pvt) return false; io->pvt = l_new(struct mesh_io_private, 1); - io->pvt->index = *(int *)opts; io->pvt->rx_regs = l_queue_new(); io->pvt->tx_pkts = l_queue_new(); - io->pvt->ready_callback = cb; - io->pvt->user_data = user_data; - - if (io->pvt->index == MGMT_INDEX_NONE) - return mesh_mgmt_list(read_info, io); + io->pvt->io = io; l_idle_oneshot(hci_init, io, NULL); diff --git a/mesh/mesh-io-generic.h b/mesh/mesh-io-generic.h index 915e376bf..546e15d62 100644 --- a/mesh/mesh-io-generic.h +++ b/mesh/mesh-io-generic.h @@ -9,3 +9,4 @@ */ extern const struct mesh_io_api mesh_io_generic; +extern const struct mesh_io_api mesh_io_mgmt; diff --git a/mesh/mesh-io-mgmt.c b/mesh/mesh-io-mgmt.c new file mode 100644 index 000000000..092e81e79 --- /dev/null +++ b/mesh/mesh-io-mgmt.c @@ -0,0 +1,787 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "monitor/bt.h" +#include "lib/bluetooth.h" +#include "lib/bluetooth.h" +#include "lib/mgmt.h" +#include "src/shared/mgmt.h" + +#include "mesh/mesh-defs.h" +#include "mesh/util.h" +#include "mesh/mesh-mgmt.h" +#include "mesh/mesh-io.h" +#include "mesh/mesh-io-api.h" +#include "mesh/mesh-io-generic.h" + +struct mesh_io_private { + struct mesh_io *io; + void *user_data; + struct l_timeout *tx_timeout; + struct l_queue *dup_filters; + struct l_queue *rx_regs; + struct l_queue *tx_pkts; + struct tx_pkt *tx; + unsigned int tx_id; + unsigned int rx_id; + uint16_t send_idx; + uint16_t interval; + uint8_t handle; + bool sending; + bool active; +}; + +struct pvt_rx_reg { + mesh_io_recv_func_t cb; + void *user_data; + uint8_t len; + uint8_t filter[0]; +}; + +struct process_data { + struct mesh_io_private *pvt; + const uint8_t *data; + uint8_t len; + struct mesh_io_recv_info info; +}; + +struct tx_pkt { + struct mesh_io_send_info info; + bool delete; + uint8_t len; + uint8_t pkt[30]; +}; + +struct tx_pattern { + const uint8_t *data; + uint8_t len; +}; + +#define DUP_FILTER_TIME 1000 +/* Accept one instance of unique message a second */ +struct dup_filter { + uint64_t data; + uint32_t instant; + uint8_t addr[6]; +} __packed; + +static struct mesh_io_private *pvt; + +static uint32_t get_instant(void) +{ + struct timeval tm; + uint32_t instant; + + gettimeofday(&tm, NULL); + instant = tm.tv_sec * 1000; + instant += tm.tv_usec / 1000; + + return instant; +} + +static uint32_t instant_remaining_ms(uint32_t instant) +{ + instant -= get_instant(); + return instant; +} + +static bool find_by_addr(const void *a, const void *b) +{ + const struct dup_filter *filter = a; + return !memcmp(filter->addr, b, 6); +} + +static void filter_timeout (struct l_timeout *timeout, void *user_data) +{ + struct dup_filter *filter; + uint32_t instant, delta; + + if (!pvt) + goto done; + + instant = get_instant(); + + filter = l_queue_peek_tail(pvt->dup_filters); + while (filter) { + delta = instant - filter->instant; + if (delta >= DUP_FILTER_TIME) { + l_queue_remove(pvt->dup_filters, filter); + l_free(filter); + } else { + l_timeout_modify(timeout, 1); + return; + } + + filter = l_queue_peek_tail(pvt->dup_filters); + } + +done: + l_timeout_remove(timeout); +} + +/* Ignore consequtive duplicate advertisements within timeout period */ +static bool filter_dups(const uint8_t *addr, const uint8_t *adv, + uint32_t instant) +{ + struct dup_filter *filter; + uint32_t instant_delta; + uint64_t data = l_get_be64(adv); + + filter = l_queue_remove_if(pvt->dup_filters, find_by_addr, addr); + if (!filter) { + filter = l_new(struct dup_filter, 1); + memcpy(filter->addr, addr, 6); + } + + /* Start filter expiration timer */ + if (!l_queue_length(pvt->dup_filters)) + l_timeout_create(1, filter_timeout, NULL, NULL); + + l_queue_push_head(pvt->dup_filters, filter); + instant_delta = instant - filter->instant; + + if (instant_delta >= DUP_FILTER_TIME || data != filter->data) { + filter->instant = instant; + filter->data = data; + return false; + } + + return true; +} + +static void process_rx_callbacks(void *v_reg, void *v_rx) +{ + struct pvt_rx_reg *rx_reg = v_reg; + struct process_data *rx = v_rx; + + if (!memcmp(rx->data, rx_reg->filter, rx_reg->len)) + rx_reg->cb(rx_reg->user_data, &rx->info, rx->data, rx->len); +} + +static void process_rx(struct mesh_io_private *pvt, int8_t rssi, + uint32_t instant, const uint8_t *addr, + const uint8_t *data, uint8_t len) +{ + struct process_data rx = { + .pvt = pvt, + .data = data, + .len = len, + .info.instant = instant, + .info.addr = addr, + .info.chan = 7, + .info.rssi = rssi, + }; + + print_packet("RX", data, len); + l_queue_foreach(pvt->rx_regs, process_rx_callbacks, &rx); +} + +static void send_cmplt(uint16_t index, uint16_t length, + const void *param, void *user_data) +{ + print_packet("Mesh Send Complete", param, length); +} + +static void event_device_found(uint16_t index, uint16_t length, + const void *param, void *user_data) +{ + const struct mgmt_ev_mesh_device_found *ev = param; + struct mesh_io *io = user_data; + const uint8_t *adv; + const uint8_t *addr; + uint32_t instant; + uint16_t adv_len; + uint16_t len = 0; + + if (ev->addr.type < 1 || ev->addr.type > 2) + return; + + instant = get_instant(); + adv = ev->eir; + adv_len = ev->eir_len; + addr = ev->addr.bdaddr.b; + + if (filter_dups(addr, adv, instant)) + return; + + //print_packet("ADV pkt", adv, adv_len); + while (len < adv_len - 1) { + uint8_t field_len = adv[0]; + + /* Check for the end of advertising data */ + if (field_len == 0) + break; + + len += field_len + 1; + + /* Do not continue data parsing if got incorrect length */ + if (len > adv_len) + break; + + /* TODO: Create an Instant to use */ + if (adv[1] >= 0x29 && adv[1] <= 0x2B) + process_rx(io->pvt, ev->rssi, instant, addr, adv + 1, adv[0]); + + adv += field_len + 1; + } +} + +static bool simple_match(const void *a, const void *b) +{ + return a == b; +} + +static bool find_by_ad_type(const void *a, const void *b) +{ + const struct tx_pkt *tx = a; + uint8_t ad_type = L_PTR_TO_UINT(b); + + return !ad_type || ad_type == tx->pkt[0]; +} + +static bool find_by_pattern(const void *a, const void *b) +{ + const struct tx_pkt *tx = a; + const struct tx_pattern *pattern = b; + + if (tx->len < pattern->len) + return false; + + return (!memcmp(tx->pkt, pattern->data, pattern->len)); +} + +static bool find_active(const void *a, const void *b) +{ + const struct pvt_rx_reg *rx_reg = a; + + /* Mesh specific AD types do *not* require active scanning, + * so do not turn on Active Scanning on their account. + */ + if (rx_reg->filter[0] < MESH_AD_TYPE_PROVISION || + rx_reg->filter[0] > MESH_AD_TYPE_BEACON) + return true; + + return false; +} + +static void mesh_up(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + int index = L_PTR_TO_UINT(user_data); + + l_debug("HCI%d Mesh up status: %d", index, status); +} + +static void le_up(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + int index = L_PTR_TO_UINT(user_data); + + l_debug("HCI%d LE up status: %d", index, status); +} + +static void ctl_up(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + int index = L_PTR_TO_UINT(user_data); + uint16_t len; + struct mgmt_cp_set_mesh *mesh; + uint8_t mesh_ad_types[] = { MESH_AD_TYPE_NETWORK, + MESH_AD_TYPE_BEACON, MESH_AD_TYPE_PROVISION }; + + l_debug("HCI%d is up status: %d", index, status); + if (status) + return; + + len = sizeof(struct mgmt_cp_set_mesh) + sizeof(mesh_ad_types); + mesh = l_malloc(len); + + mesh->enable = 1; + mesh->window = L_CPU_TO_LE16(0x1000); + mesh->period = L_CPU_TO_LE16(0x1000); + mesh->num_ad_types = sizeof(mesh_ad_types); + memcpy(mesh->ad_types, mesh_ad_types, sizeof(mesh_ad_types)); + + mesh_mgmt_send(MGMT_OP_SET_MESH_RECEIVER, index, len, mesh, + mesh_up, L_UINT_TO_PTR(index), NULL); + l_debug("done %d mesh startup", index); + + l_free(mesh); + + if (pvt->send_idx == MGMT_INDEX_NONE) { + pvt->send_idx = index; + if (pvt && pvt->io && pvt->io->ready) { + pvt->io->ready(pvt->io->user_data, true); + pvt->io->ready = NULL; + } + } +} + +static void read_info_cb(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + unsigned char le[] = { 0x01 }; + int index = L_PTR_TO_UINT(user_data); + const struct mgmt_rp_read_info *rp = param; + uint32_t current_settings, supported_settings; + + l_debug("hci %u status 0x%02x", index, status); + + if (!pvt) + return; + + if (status != MGMT_STATUS_SUCCESS) { + l_error("Failed to read info for hci index %u: %s (0x%02x)", + index, mgmt_errstr(status), status); + return; + } + + if (length < sizeof(*rp)) { + l_error("Read info response too short"); + return; + } + + current_settings = btohl(rp->current_settings); + supported_settings = btohl(rp->supported_settings); + + if (!(supported_settings & MGMT_SETTING_LE)) { + l_info("Controller hci %u does not support LE", index); + return; + } + + if (!(current_settings & MGMT_SETTING_POWERED)) { + unsigned char power[] = { 0x01 }; + + /* TODO: Initialize this HCI controller */ + l_info("Controller hci %u not in use", index); + + mesh_mgmt_send(MGMT_OP_SET_LE, index, + sizeof(le), &le, + le_up, L_UINT_TO_PTR(index), NULL); + + mesh_mgmt_send(MGMT_OP_SET_POWERED, index, + sizeof(power), &power, + ctl_up, L_UINT_TO_PTR(index), NULL); + } else { + + l_info("Controller hci %u already in use (%x)", + index, current_settings); + + /* Share this controller with bluetoothd */ + mesh_mgmt_send(MGMT_OP_SET_LE, index, + sizeof(le), &le, + ctl_up, L_UINT_TO_PTR(index), NULL); + + } +} + +static bool dev_init(struct mesh_io *io, void *opts, void *user_data) +{ + uint16_t index = *(int *)opts; + + if (!io || pvt) + return false; + + pvt = l_new(struct mesh_io_private, 1); + + pvt->send_idx = MGMT_INDEX_NONE; + + mesh_mgmt_send(MGMT_OP_READ_INFO, index, 0, NULL, + read_info_cb, L_UINT_TO_PTR(index), NULL); + + pvt->rx_id = mesh_mgmt_register(MGMT_EV_MESH_DEVICE_FOUND, + MGMT_INDEX_NONE, event_device_found, io, NULL); + pvt->tx_id = mesh_mgmt_register(MGMT_EV_MESH_PACKET_CMPLT, + MGMT_INDEX_NONE, send_cmplt, io, NULL); + + pvt->dup_filters = l_queue_new(); + pvt->rx_regs = l_queue_new(); + pvt->tx_pkts = l_queue_new(); + + pvt->io = io; + io->pvt = pvt; + + return true; +} + +static void free_rx_reg(void *user_data) +{ + struct pvt_rx_reg *rx_reg = user_data; + + l_free(rx_reg); +} + + +static bool dev_destroy(struct mesh_io *io) +{ + unsigned char param[] = { 0x00 }; + + if (io->pvt != pvt) + return true; + + mesh_mgmt_send(MGMT_OP_SET_POWERED, io->index, sizeof(param), ¶m, + NULL, NULL, NULL); + + mesh_mgmt_unregister(pvt->rx_id); + mesh_mgmt_unregister(pvt->tx_id); + l_timeout_remove(pvt->tx_timeout); + l_queue_destroy(pvt->dup_filters, l_free); + l_queue_destroy(pvt->rx_regs, free_rx_reg); + l_queue_destroy(pvt->tx_pkts, l_free); + io->pvt = NULL; + l_free(pvt); + pvt = NULL; + + return true; +} + +static bool dev_caps(struct mesh_io *io, struct mesh_io_caps *caps) +{ + struct mesh_io_private *pvt = io->pvt; + + if (!pvt || !caps) + return false; + + caps->max_num_filters = 255; + caps->window_accuracy = 50; + + return true; +} + +static void send_cancel(struct mesh_io_private *pvt) +{ + struct mgmt_cp_mesh_send_cancel remove; + + if (!pvt) + return; + + if (pvt->handle) { + remove.handle = pvt->handle; + l_debug("Cancel TX"); + mesh_mgmt_send(MGMT_OP_MESH_SEND_CANCEL, pvt->send_idx, + sizeof(remove), &remove, + NULL, NULL, NULL); + } +} + +static void tx_to(struct l_timeout *timeout, void *user_data); +static void send_queued(uint8_t status, uint16_t length, + const void *param, void *user_data) +{ + struct tx_pkt *tx = user_data; + + if (status) + l_debug("Mesh Send Failed: %d", status); + else if (param && length >= 1) + pvt->handle = *(uint8_t *) param; + + if (tx->delete) { + l_queue_remove_if(pvt->tx_pkts, simple_match, tx); + l_free(tx); + pvt->tx = NULL; + } + + tx_to(pvt->tx_timeout, pvt); +} + +static void send_pkt(struct mesh_io_private *pvt, struct tx_pkt *tx, + uint16_t interval) +{ + uint8_t buffer[sizeof(struct mgmt_cp_mesh_send) + tx->len]; + struct mgmt_cp_mesh_send *send = (void *) buffer; + uint16_t index; + size_t len; + + if (!pvt) + return; + + index = pvt->send_idx; + + len = sizeof(buffer); + memset(send, 0, len); + send->addr.type = BDADDR_LE_RANDOM; + send->instant = 0; + send->delay = 0; + send->cnt = 1; + memcpy(send->data, tx->pkt, tx->len); + mesh_mgmt_send(MGMT_OP_MESH_SEND, index, + len, send, send_queued, tx, NULL); + print_packet("Mesh Send Start", tx->pkt, tx->len); + pvt->tx = tx; +} + +static void tx_to(struct l_timeout *timeout, void *user_data) +{ + struct mesh_io_private *pvt = user_data; + struct tx_pkt *tx; + uint16_t ms; + uint8_t count; + + if (!pvt) + return; + + tx = l_queue_pop_head(pvt->tx_pkts); + if (!tx) { + l_timeout_remove(timeout); + pvt->tx_timeout = NULL; + send_cancel(pvt); + pvt->tx = NULL; + return; + } + + if (tx->info.type == MESH_IO_TIMING_TYPE_GENERAL) { + ms = tx->info.u.gen.interval; + count = tx->info.u.gen.cnt; + if (count != MESH_IO_TX_COUNT_UNLIMITED) + tx->info.u.gen.cnt--; + } else { + ms = 25; + count = 1; + } + + tx->delete = !!(count == 1); + + send_pkt(pvt, tx, ms); + + if (count == 1) { + /* Recalculate wakeup if we are responding to POLL */ + tx = l_queue_peek_head(pvt->tx_pkts); + + if (tx && tx->info.type == MESH_IO_TIMING_TYPE_POLL_RSP) { + ms = instant_remaining_ms(tx->info.u.poll_rsp.instant + + tx->info.u.poll_rsp.delay); + } + } else + l_queue_push_tail(pvt->tx_pkts, tx); + + if (timeout) { + pvt->tx_timeout = timeout; + l_timeout_modify_ms(timeout, ms); + } else + pvt->tx_timeout = l_timeout_create_ms(ms, tx_to, pvt, NULL); +} + +static void tx_worker(void *user_data) +{ + struct mesh_io_private *pvt = user_data; + struct tx_pkt *tx; + uint32_t delay; + + tx = l_queue_peek_head(pvt->tx_pkts); + if (!tx) + return; + + switch (tx->info.type) { + case MESH_IO_TIMING_TYPE_GENERAL: + if (tx->info.u.gen.min_delay == tx->info.u.gen.max_delay) + delay = tx->info.u.gen.min_delay; + else { + l_getrandom(&delay, sizeof(delay)); + delay %= tx->info.u.gen.max_delay - + tx->info.u.gen.min_delay; + delay += tx->info.u.gen.min_delay; + } + break; + + case MESH_IO_TIMING_TYPE_POLL: + if (tx->info.u.poll.min_delay == tx->info.u.poll.max_delay) + delay = tx->info.u.poll.min_delay; + else { + l_getrandom(&delay, sizeof(delay)); + delay %= tx->info.u.poll.max_delay - + tx->info.u.poll.min_delay; + delay += tx->info.u.poll.min_delay; + } + break; + + case MESH_IO_TIMING_TYPE_POLL_RSP: + /* Delay until Instant + Delay */ + delay = instant_remaining_ms(tx->info.u.poll_rsp.instant + + tx->info.u.poll_rsp.delay); + if (delay > 255) + delay = 0; + break; + + default: + return; + } + + if (!delay) + tx_to(pvt->tx_timeout, pvt); + else if (pvt->tx_timeout) + l_timeout_modify_ms(pvt->tx_timeout, delay); + else + pvt->tx_timeout = l_timeout_create_ms(delay, tx_to, pvt, NULL); +} + +static bool send_tx(struct mesh_io *io, struct mesh_io_send_info *info, + const uint8_t *data, uint16_t len) +{ + struct tx_pkt *tx; + bool sending = false; + + if (!info || !data || !len || len > sizeof(tx->pkt)) + return false; + + tx = l_new(struct tx_pkt, 1); + + memcpy(&tx->info, info, sizeof(tx->info)); + memcpy(&tx->pkt, data, len); + tx->len = len; + + if (info->type == MESH_IO_TIMING_TYPE_POLL_RSP) + l_queue_push_head(pvt->tx_pkts, tx); + else { + if (pvt->tx) + sending = true; + else + sending = !l_queue_isempty(pvt->tx_pkts); + + l_queue_push_tail(pvt->tx_pkts, tx); + } + + if (!sending) { + l_timeout_remove(pvt->tx_timeout); + pvt->tx_timeout = NULL; + l_idle_oneshot(tx_worker, pvt, NULL); + } + + return true; +} + +static bool tx_cancel(struct mesh_io *io, const uint8_t *data, uint8_t len) +{ + struct mesh_io_private *pvt = io->pvt; + struct tx_pkt *tx; + + if (!data) + return false; + + if (len == 1) { + do { + tx = l_queue_remove_if(pvt->tx_pkts, find_by_ad_type, + L_UINT_TO_PTR(data[0])); + l_free(tx); + + if (tx == pvt->tx) + pvt->tx = NULL; + + } while (tx); + } else { + struct tx_pattern pattern = { + .data = data, + .len = len + }; + + do { + tx = l_queue_remove_if(pvt->tx_pkts, find_by_pattern, + &pattern); + l_free(tx); + + if (tx == pvt->tx) + pvt->tx = NULL; + + } while (tx); + } + + if (l_queue_isempty(pvt->tx_pkts)) { + send_cancel(pvt); + l_timeout_remove(pvt->tx_timeout); + pvt->tx_timeout = NULL; + } + + return true; +} + +static bool find_by_filter(const void *a, const void *b) +{ + const struct pvt_rx_reg *rx_reg = a; + const uint8_t *filter = b; + + return !memcmp(rx_reg->filter, filter, rx_reg->len); +} + +static bool recv_register(struct mesh_io *io, const uint8_t *filter, + uint8_t len, mesh_io_recv_func_t cb, void *user_data) +{ + struct pvt_rx_reg *rx_reg; + bool active = false; + + if (!cb || !filter || !len || io->pvt != pvt) + return false; + + rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter, filter); + + free_rx_reg(rx_reg); + rx_reg = l_malloc(sizeof(*rx_reg) + len); + + memcpy(rx_reg->filter, filter, len); + rx_reg->len = len; + rx_reg->cb = cb; + rx_reg->user_data = user_data; + + l_queue_push_head(pvt->rx_regs, rx_reg); + + /* Look for any AD types requiring Active Scanning */ + if (l_queue_find(pvt->rx_regs, find_active, NULL)) + active = true; + + if (pvt->active != active) { + pvt->active = active; + /* TODO: Request active or passive scanning */ + } + + return true; +} + +static bool recv_deregister(struct mesh_io *io, const uint8_t *filter, + uint8_t len) +{ + struct pvt_rx_reg *rx_reg; + bool active = false; + + if (io->pvt != pvt) + return false; + + rx_reg = l_queue_remove_if(pvt->rx_regs, find_by_filter, filter); + + free_rx_reg(rx_reg); + + /* Look for any AD types requiring Active Scanning */ + if (l_queue_find(pvt->rx_regs, find_active, NULL)) + active = true; + + if (active != pvt->active) { + pvt->active = active; + /* TODO: Request active or passive scanning */ + } + + return true; +} + +const struct mesh_io_api mesh_io_mgmt = { + .init = dev_init, + .destroy = dev_destroy, + .caps = dev_caps, + .send = send_tx, + .reg = recv_register, + .dereg = recv_deregister, + .cancel = tx_cancel, +}; diff --git a/mesh/mesh-io-unit.c b/mesh/mesh-io-unit.c index f4b615ac8..81d9de837 100644 --- a/mesh/mesh-io-unit.c +++ b/mesh/mesh-io-unit.c @@ -28,10 +28,10 @@ #include "mesh/mesh-io-generic.h" struct mesh_io_private { + struct mesh_io *io; struct l_io *sio; void *user_data; char *unique_name; - mesh_io_ready_func_t ready_callback; struct l_timeout *tx_timeout; struct l_queue *rx_regs; struct l_queue *tx_pkts; @@ -203,14 +203,13 @@ static void unit_up(void *user_data) l_debug("Started io-unit"); - if (pvt->ready_callback) - pvt->ready_callback(pvt->user_data, true); + if (pvt->io && pvt->io->ready) + pvt->io->ready(pvt->user_data, true); l_timeout_create_ms(1, get_name, pvt, NULL); } -static bool unit_init(struct mesh_io *io, void *opt, - mesh_io_ready_func_t cb, void *user_data) +static bool unit_init(struct mesh_io *io, void *opt, void *user_data) { struct mesh_io_private *pvt; char *sk_path; @@ -247,7 +246,7 @@ static bool unit_init(struct mesh_io *io, void *opt, pvt->rx_regs = l_queue_new(); pvt->tx_pkts = l_queue_new(); - pvt->ready_callback = cb; + pvt->io = io; pvt->user_data = user_data; io->pvt = pvt; diff --git a/mesh/mesh-io.c b/mesh/mesh-io.c index 96891313a..95ee9a7f2 100644 --- a/mesh/mesh-io.c +++ b/mesh/mesh-io.c @@ -15,8 +15,11 @@ #include #include "lib/bluetooth.h" +#include "lib/mgmt.h" +#include "src/shared/mgmt.h" #include "mesh/mesh-defs.h" +#include "mesh/mesh-mgmt.h" #include "mesh/mesh-io.h" #include "mesh/mesh-io-api.h" @@ -24,86 +27,150 @@ #include "mesh/mesh-io-generic.h" #include "mesh/mesh-io-unit.h" +struct mesh_io_reg { + mesh_io_recv_func_t cb; + void *user_data; + uint8_t len; + uint8_t filter[]; +} packed; + /* List of Supported Mesh-IO Types */ static const struct mesh_io_table table[] = { - {MESH_IO_TYPE_GENERIC, &mesh_io_generic}, + {MESH_IO_TYPE_MGMT, &mesh_io_mgmt}, + {MESH_IO_TYPE_GENERIC, &mesh_io_generic}, {MESH_IO_TYPE_UNIT_TEST, &mesh_io_unit}, }; -static struct l_queue *io_list; +static struct mesh_io *default_io; -static bool match_by_io(const void *a, const void *b) +static const struct mesh_io_api *io_api(enum mesh_io_type type) { - return a == b; + uint16_t i; + + for (i = 0; i < L_ARRAY_SIZE(table); i++) { + if (table[i].type == type) { + return table[i].api; + } + } + + return NULL; } -static bool match_by_type(const void *a, const void *b) +static void refresh_rx(void *a, void *b) { - const struct mesh_io *io = a; - const enum mesh_io_type type = L_PTR_TO_UINT(b); + struct mesh_io_reg *rx_reg = a; + struct mesh_io *io = b; - return io->type == type; + if (io->api && io->api->reg) + io->api->reg(io, rx_reg->filter, rx_reg->len, rx_reg->cb, + rx_reg->user_data); } -struct mesh_io *mesh_io_new(enum mesh_io_type type, void *opts, - mesh_io_ready_func_t cb, void *user_data) +static void ctl_alert(int index, bool up, bool pwr, bool mesh, void *user_data) { + enum mesh_io_type type = L_PTR_TO_UINT(user_data); const struct mesh_io_api *api = NULL; - struct mesh_io *io; - uint16_t i; - for (i = 0; i < L_ARRAY_SIZE(table); i++) { - if (table[i].type == type) { - api = table[i].api; - break; - } - } + l_warn("up:%d pwr: %d mesh: %d", up, pwr, mesh); - io = l_queue_find(io_list, match_by_type, L_UINT_TO_PTR(type)); + /* If specific IO controller requested, honor it */ + if (default_io->favored_index != MGMT_INDEX_NONE && + default_io->favored_index != index) + return; - if (!api || !api->init || io) - return NULL; - - io = l_new(struct mesh_io, 1); + if (!up && default_io->index == index) { + /* Our controller has disappeared */ + if (default_io->api && default_io->api->destroy) { + default_io->api->destroy(default_io); + default_io->api = NULL; + } - io->type = type; - io->api = api; + /* Re-enumerate controllers */ + mesh_mgmt_list(ctl_alert, user_data); + return; + } - if (!api->init(io, opts, cb, user_data)) - goto fail; + /* If we already have an API, keep using it */ + if (!up || default_io->api) + return; - if (!io_list) - io_list = l_queue_new(); + if (mesh && type != MESH_IO_TYPE_GENERIC) { + api = io_api(MESH_IO_TYPE_MGMT); + } - if (l_queue_push_head(io_list, io)) - return io; + else if (!pwr) { + api = io_api(MESH_IO_TYPE_GENERIC); + } -fail: - if (api->destroy) - api->destroy(io); + if (api) { + default_io->index = index; + default_io->api = api; + api->init(default_io, &index, default_io->user_data); - l_free(io); - return NULL; + l_queue_foreach(default_io->rx_regs, refresh_rx, default_io); + } } -void mesh_io_destroy(struct mesh_io *io) +static void free_io(struct mesh_io *io) { - io = l_queue_remove_if(io_list, match_by_io, io); if (io && io->api && io->api->destroy) io->api->destroy(io); + l_queue_destroy(io->rx_regs, l_free); + io->rx_regs = NULL; l_free(io); + l_warn("Destroy %p", io); +} + +struct mesh_io *mesh_io_new(enum mesh_io_type type, void *opts, + mesh_io_ready_func_t cb, void *user_data) +{ + const struct mesh_io_api *api = NULL; + + /* Only allow one IO */ + if (default_io) + return NULL; + + default_io = l_new(struct mesh_io, 1); + default_io->ready = cb; + default_io->user_data = user_data; + default_io->favored_index = *(int *) opts; + default_io->rx_regs = l_queue_new(); - if (l_queue_isempty(io_list)) { - l_queue_destroy(io_list, NULL); - io_list = NULL; + if (type >= MESH_IO_TYPE_AUTO) { + if (!mesh_mgmt_list(ctl_alert, L_UINT_TO_PTR(type))) + goto fail; + + return default_io; } + + api = io_api(type); + + if (!api || !api->init) + goto fail; + + default_io->api = api; + + if (!api->init(default_io, &default_io->favored_index, user_data)) + goto fail; + + return default_io; + +fail: + free_io(default_io); + default_io = NULL; + return NULL; +} + +void mesh_io_destroy(struct mesh_io *io) +{ } bool mesh_io_get_caps(struct mesh_io *io, struct mesh_io_caps *caps) { - io = l_queue_find(io_list, match_by_io, io); + if (io != default_io) + return false; if (io && io->api && io->api->caps) return io->api->caps(io, caps); @@ -115,7 +182,17 @@ bool mesh_io_register_recv_cb(struct mesh_io *io, const uint8_t *filter, uint8_t len, mesh_io_recv_func_t cb, void *user_data) { - io = l_queue_find(io_list, match_by_io, io); + struct mesh_io_reg *rx_reg; + + if (io != default_io) + return false; + + rx_reg = l_malloc(sizeof(struct mesh_io_reg) + len); + rx_reg->cb = cb; + rx_reg->len = len; + rx_reg->user_data = user_data; + memcpy(rx_reg->filter, filter, len); + l_queue_push_head(io->rx_regs, rx_reg); if (io && io->api && io->api->reg) return io->api->reg(io, filter, len, cb, user_data); @@ -123,10 +200,24 @@ bool mesh_io_register_recv_cb(struct mesh_io *io, const uint8_t *filter, return false; } +static bool by_filter(const void *a, const void *b) +{ + const struct mesh_io_reg *rx_reg = a; + const uint8_t *filter = b; + + return rx_reg->filter[0] == filter[0]; +} + bool mesh_io_deregister_recv_cb(struct mesh_io *io, const uint8_t *filter, uint8_t len) { - io = l_queue_find(io_list, match_by_io, io); + struct mesh_io_reg *rx_reg; + + if (io != default_io) + return false; + + rx_reg = l_queue_remove_if(io->rx_regs, by_filter, filter); + l_free(rx_reg); if (io && io->api && io->api->dereg) return io->api->dereg(io, filter, len); @@ -137,10 +228,11 @@ bool mesh_io_deregister_recv_cb(struct mesh_io *io, const uint8_t *filter, bool mesh_io_send(struct mesh_io *io, struct mesh_io_send_info *info, const uint8_t *data, uint16_t len) { - io = l_queue_find(io_list, match_by_io, io); + if (io && io != default_io) + return false; if (!io) - io = l_queue_peek_head(io_list); + io = default_io; if (io && io->api && io->api->send) return io->api->send(io, info, data, len); @@ -151,7 +243,11 @@ bool mesh_io_send(struct mesh_io *io, struct mesh_io_send_info *info, bool mesh_io_send_cancel(struct mesh_io *io, const uint8_t *pattern, uint8_t len) { - io = l_queue_find(io_list, match_by_io, io); + if (io && io != default_io) + return false; + + if (!io) + io = default_io; if (io && io->api && io->api->cancel) return io->api->cancel(io, pattern, len); diff --git a/mesh/mesh-io.h b/mesh/mesh-io.h index 80ef3fa3e..9dd946cdf 100644 --- a/mesh/mesh-io.h +++ b/mesh/mesh-io.h @@ -14,8 +14,10 @@ struct mesh_io; enum mesh_io_type { MESH_IO_TYPE_NONE = 0, + MESH_IO_TYPE_UNIT_TEST, + MESH_IO_TYPE_AUTO, /* If MGMT required, add after here */ + MESH_IO_TYPE_MGMT, MESH_IO_TYPE_GENERIC, - MESH_IO_TYPE_UNIT_TEST }; enum mesh_io_timing_type { From patchwork Thu Feb 24 02:06:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Gix X-Patchwork-Id: 12757785 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 A419AC433FE for ; Thu, 24 Feb 2022 02:06:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229965AbiBXCHK (ORCPT ); Wed, 23 Feb 2022 21:07:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53886 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229943AbiBXCHH (ORCPT ); Wed, 23 Feb 2022 21:07:07 -0500 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 80BB613F1B for ; Wed, 23 Feb 2022 18:06:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645668397; x=1677204397; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=8SqBVtgDsgaVxiakoL8JO8fpMci0Q8v54T46iiGEzQU=; b=P0Ikl5szZ9Co//wten/H1CWFkKpxkYBwF+psxSAZOVBeyGbJtgCANDPR aP7/kyYVuQlb/++6s+3nQf8UuiBIWzYrNem+PH2eSzO0s5Eebnm/CpPf/ RRd74zne2RKOwed21pJTlE43CUDXJgeMSsA9ESOIlCn4jnuj3BT4hdFjt QMKsbVcumSm326Y1j9oKTA0MlHyCAQtP56UdC4hTyFvzjCF7uhsg72xrn jcleAQGBJnKar+S8GHohCUe7QyN5yvkE5MvYRiX+lWN4lVbOCqlWqAylE jyOZdkeIj7AoCDB6whsB5wMbQl5NWQRPG9zldwDzxSXkGwvC6gBr3nE4o w==; X-IronPort-AV: E=McAfee;i="6200,9189,10267"; a="239525004" X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="239525004" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:34 -0800 X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="607268575" Received: from tjsmith-mobl1.amr.corp.intel.com (HELO bgi1-mobl2.amr.corp.intel.com) ([10.209.34.213]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:34 -0800 From: Brian Gix To: linux-bluetooth@vger.kernel.org Cc: brian.gix@intel.com, inga.stotland@intel.com Subject: [PATCH 5/7] mesh: Added default "auto" to command line parsing Date: Wed, 23 Feb 2022 18:06:22 -0800 Message-Id: <20220224020624.159247-6-brian.gix@intel.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220224020624.159247-1-brian.gix@intel.com> References: <20220224020624.159247-1-brian.gix@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org While it will still be possible to request the "unit" and "hci" based transports, "auto" has been added as a default to specify "best choice" as determined by MGMT based enumeration of available controllers. --- mesh/main.c | 39 +++++++++++++++++++++++++++++++++++---- mesh/mesh.c | 6 +++++- mesh/mesh.h | 2 +- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/mesh/main.c b/mesh/main.c index dd99c3085..619b17d88 100644 --- a/mesh/main.c +++ b/mesh/main.c @@ -123,6 +123,12 @@ static void disconnect_callback(void *user_data) l_main_quit(); } +static void kill_to(struct l_timeout *timeout, void *user_data) +{ + l_timeout_remove(timeout); + l_main_quit(); +} + static void signal_handler(uint32_t signo, void *user_data) { static bool terminated; @@ -131,13 +137,38 @@ static void signal_handler(uint32_t signo, void *user_data) return; l_info("Terminating"); - l_main_quit(); + mesh_cleanup(true); + l_timeout_create(1, kill_to, NULL, NULL); terminated = true; } static bool parse_io(const char *optarg, enum mesh_io_type *type, void **opts) { - if (strstr(optarg, "generic") == optarg) { + if (strstr(optarg, "auto") == optarg) { + int *index = l_new(int, 1); + + *type = MESH_IO_TYPE_AUTO; + *opts = index; + + optarg += strlen("auto"); + if (!*optarg) { + *index = MGMT_INDEX_NONE; + return true; + } + + if (*optarg != ':') + return false; + + optarg++; + + if (sscanf(optarg, "hci%d", index) == 1) + return true; + + if (sscanf(optarg, "%d", index) == 1) + return true; + + return false; + } else if (strstr(optarg, "generic") == optarg) { int *index = l_new(int, 1); *type = MESH_IO_TYPE_GENERIC; @@ -251,7 +282,7 @@ int main(int argc, char *argv[]) } if (!io) - io = l_strdup_printf("generic"); + io = l_strdup_printf("auto"); if (!parse_io(io, &io_type, &io_opts)) { l_error("Invalid io: %s", io); @@ -295,7 +326,7 @@ done: l_free(io); l_free(io_opts); - mesh_cleanup(); + mesh_cleanup(false); l_dbus_destroy(dbus); l_main_exit(); diff --git a/mesh/mesh.c b/mesh/mesh.c index 62d650328..91cf25175 100644 --- a/mesh/mesh.c +++ b/mesh/mesh.c @@ -324,11 +324,15 @@ static void free_pending_join_call(bool failed) join_pending = NULL; } -void mesh_cleanup(void) +void mesh_cleanup(bool signaled) { struct l_dbus_message *reply; mesh_io_destroy(mesh.io); + mesh.io = NULL; + + if (signaled) + return; if (join_pending) { diff --git a/mesh/mesh.h b/mesh/mesh.h index 0f77ebc58..c30a8d1f0 100644 --- a/mesh/mesh.h +++ b/mesh/mesh.h @@ -28,7 +28,7 @@ typedef void (*prov_rx_cb_t)(void *user_data, const uint8_t *data, bool mesh_init(const char *config_dir, const char *mesh_conf_fname, enum mesh_io_type type, void *opts, mesh_ready_func_t cb, void *user_data); -void mesh_cleanup(void); +void mesh_cleanup(bool signaled); bool mesh_dbus_init(struct l_dbus *dbus); const char *mesh_status_str(uint8_t err); From patchwork Thu Feb 24 02:06:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Gix X-Patchwork-Id: 12757787 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 AC7CDC4332F for ; Thu, 24 Feb 2022 02:06:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229968AbiBXCHL (ORCPT ); Wed, 23 Feb 2022 21:07:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53946 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229941AbiBXCHJ (ORCPT ); Wed, 23 Feb 2022 21:07:09 -0500 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6A5ED2D1D0 for ; Wed, 23 Feb 2022 18:06:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645668399; x=1677204399; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=T/rOJuz5kQrr8KBYkTbp4Bw9COOu/9MaaW/oVxhBb64=; b=VdTIvPpugBRP6eYTgHYAWzbVeYaf8ozU3gQdreg0ESVpqzt2KfAdTLVW aXrUiRiM5sxU35gNrap5NsF/ozvncK8Ga+BMPSXui90sTAFGVPo1bpr5p zuCL9ljUjw26T10vd3rqOwvNxN+qBfXIZXaj0NnpKhZasFA3TmqIQlVDz zklXfB26BRVRSBT43Y47qk+3C+MeDZn2465uEQ8yImmJToVC6Pa0YwMlp /MfYfzkpBXELL8ZctbKXUD565UG2kJRDbzXV9UHWH/oYWpE2B3T3E5+oP O8ZGgQTGnarapLZX1PGdL1zA17EMqSjZRlmaCRElh5KvjPiumpgWnz5iD A==; X-IronPort-AV: E=McAfee;i="6200,9189,10267"; a="239525005" X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="239525005" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:34 -0800 X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="607268578" Received: from tjsmith-mobl1.amr.corp.intel.com (HELO bgi1-mobl2.amr.corp.intel.com) ([10.209.34.213]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:34 -0800 From: Brian Gix To: linux-bluetooth@vger.kernel.org Cc: brian.gix@intel.com, inga.stotland@intel.com Subject: [PATCH 6/7] mesh: Add new MGMT based IO transport Date: Wed, 23 Feb 2022 18:06:23 -0800 Message-Id: <20220224020624.159247-7-brian.gix@intel.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220224020624.159247-1-brian.gix@intel.com> References: <20220224020624.159247-1-brian.gix@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org Adds required new modules to support kernel based MGMT tx/rx --- Makefile.mesh | 9 ++++----- mesh/mesh-io-generic.h | 1 - mesh/mesh-io-mgmt.c | 2 +- mesh/mesh-io-mgmt.h | 11 +++++++++++ mesh/mesh-io-unit.c | 2 +- mesh/mesh-io.c | 1 + 6 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 mesh/mesh-io-mgmt.h diff --git a/Makefile.mesh b/Makefile.mesh index fc28b0557..3047f362b 100644 --- a/Makefile.mesh +++ b/Makefile.mesh @@ -13,12 +13,11 @@ endif mesh_sources = mesh/mesh.h mesh/mesh.c \ mesh/net-keys.h mesh/net-keys.c \ mesh/mesh-io.h mesh/mesh-io.c \ - mesh/mesh-mgmt.c mesh/mesh-mgmt.h \ + mesh/mesh-mgmt.h mesh/mesh-mgmt.c \ mesh/error.h mesh/mesh-io-api.h \ - mesh/mesh-io-generic.h \ - mesh/mesh-io-generic.c \ - mesh/mesh-io-unit.h \ - mesh/mesh-io-unit.c \ + mesh/mesh-io-unit.h mesh/mesh-io-unit.c \ + mesh/mesh-io-mgmt.h mesh/mesh-io-mgmt.c \ + mesh/mesh-io-generic.h mesh/mesh-io-generic.c \ mesh/net.h mesh/net.c \ mesh/crypto.h mesh/crypto.c \ mesh/friend.h mesh/friend.c \ diff --git a/mesh/mesh-io-generic.h b/mesh/mesh-io-generic.h index 546e15d62..915e376bf 100644 --- a/mesh/mesh-io-generic.h +++ b/mesh/mesh-io-generic.h @@ -9,4 +9,3 @@ */ extern const struct mesh_io_api mesh_io_generic; -extern const struct mesh_io_api mesh_io_mgmt; diff --git a/mesh/mesh-io-mgmt.c b/mesh/mesh-io-mgmt.c index 092e81e79..cf18966fb 100644 --- a/mesh/mesh-io-mgmt.c +++ b/mesh/mesh-io-mgmt.c @@ -29,7 +29,7 @@ #include "mesh/mesh-mgmt.h" #include "mesh/mesh-io.h" #include "mesh/mesh-io-api.h" -#include "mesh/mesh-io-generic.h" +#include "mesh/mesh-io-mgmt.h" struct mesh_io_private { struct mesh_io *io; diff --git a/mesh/mesh-io-mgmt.h b/mesh/mesh-io-mgmt.h new file mode 100644 index 000000000..455691c8f --- /dev/null +++ b/mesh/mesh-io-mgmt.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * + */ + +extern const struct mesh_io_api mesh_io_mgmt; diff --git a/mesh/mesh-io-unit.c b/mesh/mesh-io-unit.c index 81d9de837..f818140b4 100644 --- a/mesh/mesh-io-unit.c +++ b/mesh/mesh-io-unit.c @@ -25,7 +25,7 @@ #include "mesh/dbus.h" #include "mesh/mesh-io.h" #include "mesh/mesh-io-api.h" -#include "mesh/mesh-io-generic.h" +#include "mesh/mesh-io-unit.h" struct mesh_io_private { struct mesh_io *io; diff --git a/mesh/mesh-io.c b/mesh/mesh-io.c index 95ee9a7f2..8bae7ff7f 100644 --- a/mesh/mesh-io.c +++ b/mesh/mesh-io.c @@ -24,6 +24,7 @@ #include "mesh/mesh-io-api.h" /* List of Mesh-IO Type headers */ +#include "mesh/mesh-io-mgmt.h" #include "mesh/mesh-io-generic.h" #include "mesh/mesh-io-unit.h" From patchwork Thu Feb 24 02:06:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Gix X-Patchwork-Id: 12757786 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 1D214C43217 for ; Thu, 24 Feb 2022 02:06:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229969AbiBXCHM (ORCPT ); Wed, 23 Feb 2022 21:07:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54044 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229964AbiBXCHK (ORCPT ); Wed, 23 Feb 2022 21:07:10 -0500 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1E1A4BC14 for ; Wed, 23 Feb 2022 18:06:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1645668401; x=1677204401; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=XLo09VOnrfXFZDVVxDI4lAY3LPFNp9RKr5Q5sFswc5k=; b=HL5hybJHPAPQhKzW6tR3e+mq7UwC0IDN02grkGcg6w+EQZDmED+IdGiF p2LCurcvajP9G+5Gh0TCUhzQveF1WxmcPtxGp3a1VEkhb1jYe2zOMn+Ca QjWPU/H9Eza1AKe7Qctm8MeUs9mniFxZ7TvVqzSemzzFQ0OcrUvOus7H8 g+merrdUFeJJqctNyJS1FG8D0QSaWFmT2uY6cDeR9A04yw6HPvanYaFpX X4M6iEPvlthTxi5nm4SNkrSlT92bcSiUVlUV2FAzD9NJLBz+yuP8mmhG7 SANwey4b4KQ3TvGHmiLV+gejiaXlbCWl3gJlaeVjpfQJnQJ7iJXAslSuN A==; X-IronPort-AV: E=McAfee;i="6200,9189,10267"; a="239525008" X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="239525008" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:34 -0800 X-IronPort-AV: E=Sophos;i="5.88,392,1635231600"; d="scan'208";a="607268582" Received: from tjsmith-mobl1.amr.corp.intel.com (HELO bgi1-mobl2.amr.corp.intel.com) ([10.209.34.213]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Feb 2022 18:06:34 -0800 From: Brian Gix To: linux-bluetooth@vger.kernel.org Cc: brian.gix@intel.com, inga.stotland@intel.com Subject: [PATCH 7/7] mesh: Make Provisioning requests more IO compatible Date: Wed, 23 Feb 2022 18:06:24 -0800 Message-Id: <20220224020624.159247-8-brian.gix@intel.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220224020624.159247-1-brian.gix@intel.com> References: <20220224020624.159247-1-brian.gix@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org Requests longer (half second) periods between discrete PB-ADV transmissions. This prevents the controller from being overwhelmed by PB-ADV packets when daemon is also an active mesh network member. --- mesh/pb-adv.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mesh/pb-adv.c b/mesh/pb-adv.c index 83f922aa8..180b16258 100644 --- a/mesh/pb-adv.c +++ b/mesh/pb-adv.c @@ -23,6 +23,8 @@ #include "mesh/provision.h" #include "mesh/pb-adv.h" +#include "mesh/util.h" + struct pb_adv_session { mesh_prov_open_func_t open_cb; @@ -158,7 +160,7 @@ static void send_adv_segs(struct pb_adv_session *session, const uint8_t *data, l_debug("max_seg: %2.2x", max_seg); l_debug("size: %2.2x, CRC: %2.2x", size, buf[9]); - pb_adv_send(session, MESH_IO_TX_COUNT_UNLIMITED, 200, + pb_adv_send(session, MESH_IO_TX_COUNT_UNLIMITED, 500, buf, init_size + 10); consumed = init_size; @@ -174,7 +176,7 @@ static void send_adv_segs(struct pb_adv_session *session, const uint8_t *data, buf[6] = (i << 2) | 0x02; memcpy(buf + 7, data + consumed, seg_size); - pb_adv_send(session, MESH_IO_TX_COUNT_UNLIMITED, 200, + pb_adv_send(session, MESH_IO_TX_COUNT_UNLIMITED, 500, buf, seg_size + 7); consumed += seg_size; @@ -270,7 +272,8 @@ static void send_ack(struct pb_adv_session *session, uint8_t trans_num) ack.trans_num = trans_num; ack.opcode = PB_ADV_ACK; - pb_adv_send(session, 1, 100, &ack, sizeof(ack)); + pb_adv_send(session, MESH_IO_TX_COUNT_UNLIMITED, 500, + &ack, sizeof(ack)); } static void send_close_ind(struct pb_adv_session *session, uint8_t reason)