From patchwork Mon Oct 14 05:22:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Junho Lee X-Patchwork-Id: 835899 Received: from mail-ot1-f51.google.com (mail-ot1-f51.google.com [209.85.210.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 39C00231C9A for ; Mon, 14 Oct 2024 05:22:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1728883361; cv=none; b=uicmfQcfHOM/2epIDGlq7gY93fXA4L/iEkwdNEpEIw+ocCGncKjf/oIx0VR/2dyiiM2FnzhU+w4+5wO+SWlhs9BvwlJ1JfWYsxwZ34J0KE8lsVc3GJUndEIjW5QQxGkJ6PBeUYPCF6S+sAp/1S5fWIGUtAU4YxjILAtRuDwsyKE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1728883361; c=relaxed/simple; bh=faK6XWq8mtyX5B6ULPT7a+PZyqj05h2pVIOwz15J7RE=; h=Message-ID:Date:From:To:Subject:MIME-Version:Content-Type: Content-Disposition; b=FOep5DVb9iJQ+N91oMABQ1mSE25dKRUa8//jZg7i4w/4lVMnYYtHu872IRwnoe4gVyxJcT8fKe8ViVnJNay3An5szXR6Fd3Q47a50j6WNATgkogRLr7d/9keQSWlq1kfWaG1KHwaBKr6MLnfweoljoRZEBy7gcTxWiwRYHAG1uE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=EJwvo/xa; arc=none smtp.client-ip=209.85.210.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="EJwvo/xa" Received: by mail-ot1-f51.google.com with SMTP id 46e09a7af769-7170d0edab6so1878825a34.0 for ; Sun, 13 Oct 2024 22:22:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1728883359; x=1729488159; darn=vger.kernel.org; h=content-disposition:mime-version:subject:to:from:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=tRx3IC4NYZcXkgJI8J3F4oa+SBfBLkFGe9LUx01FzGc=; b=EJwvo/xa2BEm89hvltLY1ohqk+GTbTTFCag5AHCyQx/EjHLWdnt1c3xAb+h5wDs/TQ BwIhFI6vMlBl5qdp77FNBk27xcFrDfhRZ5wKNDqSLLQP3brcrlsOsHr3nmc/D1wB08sa 0UjRCXHNDMmaRq2jwQAXMM/+7ioFsEMrhLPr49CPR3GKZgikqhiYyxSaaUYqVmn2tFPN 9I1t3KhAFChnlDuKA6g0O6/xO2HQAKiMXD6kJv4ImRziR9bnkWPE81XkQg3tlbmXxgkI JICLkcby7m1JT52oj1vNtrCP/I3DvkQf8BNS1TJzF7io8NFQWDTIYOxAhJRAzZxCtYND Dsgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728883359; x=1729488159; h=content-disposition:mime-version:subject:to:from:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=tRx3IC4NYZcXkgJI8J3F4oa+SBfBLkFGe9LUx01FzGc=; b=JapyOAyuS9aFL3dzLz4oTWF4rp8K6JF2NgRGcjKo08oYfm4sjxUgRPw1hS1IR4Lt6F /pkzFGB+7+aD55gmz5pVran7gc81ZJHLJQjtvHzIDNHK0xBOEfDHC/jqaMk0M6npi4We jnpT5z6xb9xXBCS7z7TffaluICvgkKtyBG/pVFLpW0+HJrIcCVoUaJTBJj+PDUstmQMd VUVn+RGVa71/9MT/9c1cTIe7Blk3qQ62dta5OlxPnzjkUssNduBXurIpDZ9rzq2sAFrd 92bSmvL8UEElr9JXpxNyuagemFRUdtERlIq2odYPcESnGSRZ9UuwQaFYOBFo9lAg8119 t77w== X-Gm-Message-State: AOJu0YwDDC4n1371Fd+HQv0lg+2nEaOn6VRE4vu3SvaSlOdOzxM3aBu2 qpi6EXQ6VOAGw12vNQRe25A+OhnOByQKTLDB+1vBwRJ5ZfcgxHsq+sAJjw== X-Google-Smtp-Source: AGHT+IGV8ukpe4nxWiL7WIMGbWs7d4asRCQBB+XSFCUVWtyTPjZdqedzGt+g8+AoWWcOKlaHpOJ7sQ== X-Received: by 2002:a05:6359:4c9b:b0:1ba:5118:ebee with SMTP id e5c5f4694b2df-1c32ba41305mr271471155d.8.1728883358808; Sun, 13 Oct 2024 22:22:38 -0700 (PDT) Received: from JUNHO-NEOSTACK. ([221.154.134.3]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-71e56e0d9f9sm2921660b3a.79.2024.10.13.22.22.37 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 13 Oct 2024 22:22:38 -0700 (PDT) Message-ID: <670caa9e.050a0220.1d90eb.58b8@mx.google.com> X-Google-Original-Message-ID: Date: Mon, 14 Oct 2024 14:22:36 +0900 From: Junho Lee To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ v2 2/4] mesh: Add mesh conf for SAR Transmitter and Receiver Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline This allows you to set the SAR Transitter state and SAR Receiver state in the mesh conf file. --- mesh/mesh-main.conf | 107 ++++++++++++++++++++++++++++++++++++++++++++ mesh/mesh.c | 80 ++++++++++++++++++++++++++++++--- 2 files changed, 181 insertions(+), 6 deletions(-) diff --git a/mesh/mesh-main.conf b/mesh/mesh-main.conf index aca9e6fa5..01f4c3d23 100644 --- a/mesh/mesh-main.conf +++ b/mesh/mesh-main.conf @@ -41,3 +41,110 @@ # Setting this value to zero means there's no timeout. # Defaults to 60. #ProvTimeout = 60 + + +[SARTransmitter] + +# Transmission interval step between segments of a message. +# Interval is measured in milliseconds and calculated using the following +# formula: +# +# (SegIntervalStep + 1) * 10 ms. +# +# Valid range 0-15. +# Defaults to 5. +#SegIntervalStep = 5 + +# Maximum number of retransmissions of segments to a unicast destination. +# Valid range 0-15. +# Defaults to 2. +#UnicastRetransCount = 2 + +# Maximum number of retransmissions of segments to a unicast destination when no +# acknowledgment is newly received during the retransmission interval. +# This value sould be set to greater than AckRetransCount on a peer node. +# Valid range 0-15. +# Defaults to 2. +#UnicastRetransWithoutProgressCount = 2 + +# Retransmission interval step between segments of a meesage to a unicast +# destination. +# Interval is measured in milliseconds and calculated using the following +# formula: +# +# (UnicastRetransIntervalStep + 1) * 25 ms +# +# Valid range 0-15. +# Defaults to 7. +#UnicastRetransIntervalStep = 7 + +# Interval step between segments of a message to a unicast destination that +# increases proportionally to (ttl - 1) when ttl is over 0. +# Increment is measured in milliseconds and calculated using the following +# formula: +# +# (UnicastRetransIntervalIncrement + 1) * 25 ms +# +# Valid range 0-15. +# Defaults to 1. +#UnicastRetransIntervalIncrement = 1 + +# Maximum number of retransmissions of segments to a multicast destination. +# Valid range 0-15. +# Defaults to 2. +#MulticastRetransCount = 2 + +# Retransmission interval step between segments of a meesage to a multicast +# destination. +# Interval is measured in milliseconds and calculated using the following +# formula: +# +# (MulticastRetransIntervalStep + 1) * 25 ms +# +# Valid range 0-15. +# Defaults to 8. +#MulticastRetransIntervalStep = 8 + +[SARReceiver] + +# Threshold number of segments in a message to retransmit acknowledgment +# messages. If the number of segments in a message exceeds SegmentsThreshold, +# retransmit the Acknowledgment message by AckRetransCount. +# Valid range 0-31. +# Defaults to 3 +#SegmentsThreshold = 3 + +# Interval increment between acknowledgment messages. +# Increment is measured in segments and calculated using the following formula: +# +# AckDelayIncrement + 1.5 +# +# Valid range 0-7 +# Defaults to 1 +#AckDelayIncrement = 1 + +# Maximum number of retransmissions of acknowledgment messages. +# Valid range 0-3 +# Defaults to 0 +#AckRetransCount = 0 + +# Timeout to discard a segmented message when no more new segments of the +# message are coming in. +# Timeout is measured in seconds and calculated using the following formula: +# +# (DiscardTimeout + 1) * 5 sec +# +# Valid range 0-15 +# Defaults to 1 +#DiscardTimeout = 1 + +# Interval between received segments of a message. This is used to control rate +# of transmission of acknowledgment messages. +# Increment is measured in milliseconds and calculated using the following +# formula: +# +# (ReceiverSegIntervalStep + 1) * 10 ms +# +# Valid range 0-15 +# Defaults to 5 +#ReceiverSegIntervalStep = 5 diff --git a/mesh/mesh.c b/mesh/mesh.c index f89230b6c..17236c110 100644 --- a/mesh/mesh.c +++ b/mesh/mesh.c @@ -248,16 +248,11 @@ void mesh_get_sar_receiver(void *sar_rxr) memcpy(sar_rxr, &mesh_sar_rxr, sizeof(struct mesh_sar_receiver)); } -static void parse_settings(const char *mesh_conf_fname) +static void parse_mesh_general(const struct l_settings *settings) { - struct l_settings *settings; char *str; uint32_t value; - settings = l_settings_new(); - if (!l_settings_load_from_file(settings, mesh_conf_fname)) - goto done; - str = l_settings_get_string(settings, "General", "Beacon"); if (str) { if (!strcasecmp(str, "true")) @@ -290,6 +285,79 @@ static void parse_settings(const char *mesh_conf_fname) if (l_settings_get_uint(settings, "General", "ProvTimeout", &value)) mesh.prov_timeout = value; +} + +static void parse_mesh_sar(const struct l_settings *settings) +{ + uint32_t value; + + if (l_settings_get_uint(settings, "SARTransmitter", "SegIntervalStep", + &value) && value <= 15) + mesh_sar_txr.seg_int_step = value; + + if (l_settings_get_uint(settings, "SARTransmitter", + "UnicastRetransCount", + &value) && value <= 15) + mesh_sar_txr.unicast_rtx_cnt = value; + + if (l_settings_get_uint(settings, "SARTransmitter", + "UnicastRetransWithoutProgressCount", + &value) && value <= 15) + mesh_sar_txr.unicast_rtx_without_prog_cnt = value; + + if (l_settings_get_uint(settings, "SARTransmitter", + "UnicastRetransIntervalStep", + &value) && value <= 15) + mesh_sar_txr.unicast_rtx_int_step = value; + + if (l_settings_get_uint(settings, "SARTransmitter", + "UnicastRetransIntervalIncrement", + &value) && value <= 15) + mesh_sar_txr.unicast_rtx_int_inc = value; + + if (l_settings_get_uint(settings, "SARTransmitter", + "MulticastRetransCount", + &value) && value <= 15) + mesh_sar_txr.multicast_rtx_cnt = value; + + if (l_settings_get_uint(settings, "SARTransmitter", + "MulticastRetransIntervalStep", + &value) && value <= 15) + mesh_sar_txr.multicast_rtx_int_step = value; + + if (l_settings_get_uint(settings, "SARReceiver", "SegmentsThreshold", + &value) && value <= 31) + mesh_sar_rxr.seg_threshold = value; + + if (l_settings_get_uint(settings, "SARReceiver", "AckDelayIncrement", + &value) && value <= 7) + mesh_sar_rxr.ack_delay_inc = value; + + if (l_settings_get_uint(settings, "SARReceiver", "AckRetransCount", + &value) && value <= 3) + mesh_sar_rxr.ack_rtx_cnt = value; + + if (l_settings_get_uint(settings, "SARReceiver", "DiscardTimeout", + &value) && value <= 15) + mesh_sar_rxr.discard_timeout = value; + + if (l_settings_get_uint(settings, "SARReceiver", + "ReceiverSegIntervalStep", + &value) && value <= 15) + mesh_sar_rxr.receiver_seg_int_step = value; +} + +static void parse_settings(const char *mesh_conf_fname) +{ + struct l_settings *settings; + + settings = l_settings_new(); + if (!l_settings_load_from_file(settings, mesh_conf_fname)) + goto done; + + parse_mesh_general(settings); + parse_mesh_sar(settings); + done: l_settings_free(settings); } From patchwork Mon Oct 14 05:23:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Junho Lee X-Patchwork-Id: 835898 Received: from mail-pg1-f179.google.com (mail-pg1-f179.google.com [209.85.215.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EF8A9231C9A for ; Mon, 14 Oct 2024 05:23:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1728883415; cv=none; b=NhxaJvS5TuTZJCNaHQzcXl0Jd2Jz9XStUMdZeXAlz1APBsFg8+62ujtFw+XTg98zVTofr5OLvjI9WFHRJQ4ViIRJhPNk91wt4Yu6w+bzZZ6xbQKi8OUYlE0uqSUTzb+rRub/HoYBzxS0XySwedq1BcI4kB4p9nbhsDgExhieQwk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1728883415; c=relaxed/simple; bh=mOP+3hYa6+AK08a6UpOqnUyx/0ifCRmGMLKyrExB0ik=; h=Message-ID:Date:From:To:Subject:MIME-Version:Content-Type: Content-Disposition; b=HCU48rezOHUBlxtqFbmfWZeWqnDbd50OzFMnw8Cl9gSXhbKufWgRxXvdl8c/tktP6gypIJ0tHgsaytVWX9vjdvecsS+jdKap+S/N/ihYh6vsWtfoMIlCcOh4iSUyBqNqvio+9BB/oT6XbpFE5zBGhWyKpg/9A9rzztVSMqFPERE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=cH4eLDY0; arc=none smtp.client-ip=209.85.215.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="cH4eLDY0" Received: by mail-pg1-f179.google.com with SMTP id 41be03b00d2f7-7ea7ad1e01fso593121a12.0 for ; Sun, 13 Oct 2024 22:23:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1728883412; x=1729488212; darn=vger.kernel.org; h=content-disposition:mime-version:subject:to:from:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=tTEhZXeXvYCtqYbbp1VU57C6tf++vWvSo01WkePNrdw=; b=cH4eLDY0+nStqssqxPgulqKUqPovM5KiEsaAmZQbFG/ofWqbOJE3mwB4vEcCIw+jbs fK3Qg5bLLvSWNUc/OViStheLV0qzFeRVOQVTyqtCLUWHklgVIboApVZVqclNiYKuKkqC 0dMzFwz9y7xW8HgBhWUqGYfLyNjYOiQLr2Tsy3zwpVqsTAFyk02rgxnSDtx0rorw6BuN 9tYa7xZIeHDl7Wu6Kg5fz+S4efK4M4FTcPstVER4baDV+tsgi1kBVchKNpjFVqzUayZA frCatW5qf9PjKOCVBl3TaBc+UQiH7MOGt1FWKhAS7p6PhhpSFDAyiFmhYER0nu+k20Kt VY/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728883412; x=1729488212; h=content-disposition:mime-version:subject:to:from:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=tTEhZXeXvYCtqYbbp1VU57C6tf++vWvSo01WkePNrdw=; b=KJ6eSt5hUAgjZxKjlXIYmfJcBEJHbFsB2em/DeYxkdLZBPIRW25dxPAHA/cojSdYNL Z0EQHtNPYuqmJU+zC+73XxzU1L/fkEgnO9A51p4TWkNwHDj2k/oZt6PriAlXIpGZEY/d 3Rp0wvzPrKGhiWH8LqMy1b9a4sZ6iabhNBV0N10VNBBgH921TPObacgB6w/+rGa3d7Yp ZKJysSuSY+97/ON2GYqg1DKdazUjvbVy7SGECHudNBDQ40oTnB8Dr5/W03H7XeVE91p8 2ielcldp6+FAsfXt3z0wau4PlAY0beOEAlKfQTt4yTWR4rwVitbmB3ZSQpJACIuPdzm+ GwFQ== X-Gm-Message-State: AOJu0YybHuV8yYncfa7prfNMjE/Zrjyymo6gki31LXvvsX0VCAgfbowR FBvY1z2WBEvY4TJ50qiJDYtvCmw3Mp/rSb1BZTa4PWC8PYsqiVl1X9FcbA== X-Google-Smtp-Source: AGHT+IGeRC3/1+ZLzVtd4ywnhiV5nC8FvI8sla+2JgqHOT6H3LZAC4fJgUiv45uC6cQwpdfmy5F9jA== X-Received: by 2002:a05:6a20:c888:b0:1c8:de01:e7e5 with SMTP id adf61e73a8af0-1d8bc8c8c47mr12586068637.15.1728883411450; Sun, 13 Oct 2024 22:23:31 -0700 (PDT) Received: from JUNHO-NEOSTACK. ([221.154.134.3]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-71e51081a33sm3393409b3a.133.2024.10.13.22.23.30 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 13 Oct 2024 22:23:31 -0700 (PDT) Message-ID: <670caad3.a70a0220.273f1.6612@mx.google.com> X-Google-Original-Message-ID: Date: Mon, 14 Oct 2024 14:23:28 +0900 From: Junho Lee To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ v2 4/4] mesh: Add features of Segmented Control message Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline According to Mesh Protocol v1.1, with the addition of Transport Control messages with variable length PDU such as 'Friend Subscription List Add' and 'Friend Subscription List Remove', it is necessary to support segmentation in the Lower Transport layer because the Upper Transport Control PDU can be larger than the size of a single Network PDU. This is achieved by performing the segmentation function for Transport Control messages, where the segmentation of Transport Control messages is the same as for Access messages, but with different message fields and lengths, so the segmentation is controlled by branching. It was written to perform the function as little as possible without changing the existing design. We avoided modifying arguments outside of static functions, and kept the existing working design unchanged. However, some macro definitions had to be modified because they were written based on Access messages, so we changed them to work by comparing the Transport Control message flag. This commit does not support segmentation for control messages as a friend of Low Power Nodes. This should be added later. --- mesh/crypto.c | 69 +++++----- mesh/net.c | 279 +++++++++++++++++++++++++--------------- mesh/net.h | 33 ++++- unit/test-mesh-crypto.c | 4 +- 4 files changed, 246 insertions(+), 139 deletions(-) diff --git a/mesh/crypto.c b/mesh/crypto.c index b712a2654..08548031b 100644 --- a/mesh/crypto.c +++ b/mesh/crypto.c @@ -532,7 +532,8 @@ bool mesh_crypto_packet_build(bool ctl, uint8_t ttl, uint8_t *packet, uint8_t *packet_len) { uint32_t hdr; - size_t n; + size_t hdr_offset = 9; + size_t payload_offset = 10; if (seq > SEQ_MASK) return false; @@ -543,50 +544,44 @@ bool mesh_crypto_packet_build(bool ctl, uint8_t ttl, l_put_be16(src, packet + 5); l_put_be16(dst, packet + 7); - n = 9; - if (!ctl) { - uint32_t tmp = segmented ? 0x1 : 0; + hdr = (segmented ? 0x1 : 0) << SEG_HDR_SHIFT; + + if (segmented) { + hdr |= (seqZero & SEQ_ZERO_MASK) << SEQ_ZERO_HDR_SHIFT; + hdr |= (segO & SEG_MASK) << SEGO_HDR_SHIFT; + hdr |= (segN & SEG_MASK) << SEGN_HDR_SHIFT; + payload_offset += 3; + } - hdr = tmp << SEG_HDR_SHIFT; + if (!ctl) { hdr |= (key_aid & KEY_ID_MASK) << KEY_HDR_SHIFT; if (segmented) { hdr |= szmic << SZMIC_HDR_SHIFT; - hdr |= (seqZero & SEQ_ZERO_MASK) << SEQ_ZERO_HDR_SHIFT; - hdr |= (segO & SEG_MASK) << SEGO_HDR_SHIFT; - hdr |= (segN & SEG_MASK) << SEGN_HDR_SHIFT; } - l_put_be32(hdr, packet + n); - - /* Only first octet is valid for unsegmented messages */ - if (segmented) - n += 4; - else - n += 1; - - memcpy(packet + n, payload, payload_len); - - l_put_be32(0x00000000, packet + payload_len + n); - if (packet_len) - *packet_len = payload_len + n + 4; } else { if ((opcode & OPCODE_MASK) != opcode) return false; - hdr = opcode << KEY_HDR_SHIFT; - l_put_be32(hdr, packet + n); - n += 1; + hdr |= opcode << OPCODE_HDR_SHIFT; + } + + l_put_be32(hdr, packet + hdr_offset); - memcpy(packet + n, payload, payload_len); - n += payload_len; + memcpy(packet + payload_offset, payload, payload_len); - l_put_be64(0x0000000000000000, packet + n); + if (!ctl) { + l_put_be32(0x00000000, packet + payload_offset + payload_len); if (packet_len) - *packet_len = n + 8; + *packet_len = payload_offset + payload_len + 4; + } else { + l_put_be64(0x0000000000000000, packet + payload_offset + + payload_len); + if (packet_len) + *packet_len = payload_offset + payload_len + 8; } - return true; } @@ -665,6 +660,22 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len, if (payload_len) *payload_len = packet_len - 9; + } else if (is_segmented) { + if (seqZero) + *seqZero = (hdr >> SEQ_ZERO_HDR_SHIFT) & + SEQ_ZERO_MASK; + + if (segO) + *segO = (hdr >> SEGO_HDR_SHIFT) & SEG_MASK; + + if (segN) + *segN = (hdr >> SEGN_HDR_SHIFT) & SEG_MASK; + + if (payload) + *payload = packet + 13; + + if (payload_len) + *payload_len = packet_len - 13; } else { if (payload) *payload = packet + 10; diff --git a/mesh/net.c b/mesh/net.c index 82c812b73..215db995c 100644 --- a/mesh/net.c +++ b/mesh/net.c @@ -179,12 +179,20 @@ struct mesh_sar { uint16_t src; uint16_t remote; uint16_t len; - bool szmic; bool segmented; + bool ctl; bool frnd; bool frnd_cred; uint8_t ttl; - uint8_t key_aid; + union { + struct { + uint8_t key_aid; + bool szmic; + }; /* Access message */ + struct { + uint8_t opcode; + }; /* Transport Control message */ + }; uint8_t buf[4]; /* Large enough for ACK-Flags and MIC */ }; @@ -1964,7 +1972,7 @@ static bool msg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, hdr |= (uint32_t) 0x01 << SEG_HDR_SHIFT; hdr |= szmic << SZMIC_HDR_SHIFT; hdr |= (seqZero & SEQ_ZERO_MASK) << SEQ_ZERO_HDR_SHIFT; - hdr |= SEG_MAX(true, size) << SEGN_HDR_SHIFT; + hdr |= SEG_MAX(false, true, size) << SEGN_HDR_SHIFT; } if (friend_packet_queue(net, iv_index, false, frnd_ttl, @@ -2141,11 +2149,18 @@ static void friend_seg_rxed(struct mesh_net *net, frnd_msg->cnt_in++; } +static bool ctl_rxed(struct mesh_net *net, uint32_t net_key_id, + uint32_t iv_index, uint8_t ttl, + uint32_t seq, uint16_t src, + uint16_t dst, uint8_t opcode, + int8_t rssi, const uint8_t *pkt, + uint8_t len); + static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, uint8_t ttl, uint32_t seq, uint16_t net_idx, - uint16_t src, uint16_t dst, - uint8_t key_aid, + uint16_t src, uint16_t dst, bool ctl, + uint8_t opcode, uint8_t key_aid, bool szmic, uint16_t seqZero, uint8_t segO, uint8_t segN, const uint8_t *data, uint8_t size) @@ -2194,10 +2209,15 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, l_debug("RXed (old: %04x %06x size:%d) %d of %d", seqZero, seq, size, segO, segN); /* Sanity Check--> certain things must match */ - if (SEG_MAX(true, sar->len) != segN || - sar->key_aid != key_aid) + if (SEG_MAX(ctl, true, sar->len) != segN) return false; + if (!ctl && sar->key_aid != key_aid) { + return false; + } else if (ctl && sar->opcode != opcode) { + return false; + } + if (sar->flags == expected) { /* * According to MshPRTv1.1: 3.5.3.4, if the destination @@ -2217,7 +2237,7 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, return true; } } else { - uint16_t len = MAX_SEG_TO_LEN(segN); + uint16_t len = MAX_SEG_TO_LEN(ctl, segN); l_debug("RXed (new: %04x %06x size: %d len: %d) %d of %d", seqZero, seq, size, len, segO, segN); @@ -2228,9 +2248,12 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, sar->src = dst; sar->remote = src; sar->seqZero = seqZero; - sar->key_aid = key_aid; sar->len = len; sar->net_idx = net_idx; + if (ctl) + sar->opcode = opcode; + else + sar->key_aid = key_aid; sar_in = mesh_sar_rx_new(); sar_in->sar = sar; @@ -2270,14 +2293,14 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, l_timeout_remove(sar_in->msg_timeout); sar_in->msg_timeout = NULL; - seg_off = segO * MAX_SEG_LEN; + seg_off = segO * MAX_SEG_LEN(ctl); memcpy(sar->buf + seg_off, data, size); sar->flags |= this_seg_flag; sar->ttl = ttl; /* Msg length only definitive on last segment */ if (segO == segN) - sar->len = segN * MAX_SEG_LEN + size; + sar->len = segN * MAX_SEG_LEN(ctl) + size; /* Send ACK only if DST is unicast address. */ if (IS_UNICAST(dst)) { @@ -2290,9 +2313,21 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, /* Got it all */ send_net_ack(net, sar, expected); - msg_rxed(net, frnd, iv_index, ttl, seq, net_idx, - sar->remote, dst, key_aid, true, szmic, - sar->seqZero, sar->buf, sar->len); + if (!ctl) { + msg_rxed(net, frnd, iv_index, ttl, seq, net_idx, + sar->remote, dst, key_aid, true, szmic, + sar->seqZero, sar->buf, sar->len); + } else { + struct mesh_subnet *subnet = l_queue_find(net->subnets, + match_key_index, + L_UINT_TO_PTR(net_idx)); + if (!subnet) + return false; + + ctl_rxed(net, subnet->net_key_tx, iv_index, ttl, + seq, sar->remote, dst, + opcode, 0, sar->buf, sar->len); + } /* * Delay SAR removal to be able to acknowledge a transaction @@ -2312,7 +2347,7 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, return false; } -static bool ctl_received(struct mesh_net *net, uint32_t net_key_id, +static bool ctl_rxed(struct mesh_net *net, uint32_t net_key_id, uint32_t iv_index, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dst, @@ -2324,7 +2359,11 @@ static bool ctl_received(struct mesh_net *net, uint32_t net_key_id, uint8_t n = 0; uint16_t net_idx; - if (ttl > 1) { + /* TODO: If length is greater than 11, it must be segmented, so it must + * be able to handle Segmented Control messages when acting as a friend + * node. + */ + if (ttl > 1 && len <= 11) { uint32_t hdr = opcode << OPCODE_HDR_SHIFT; uint8_t frnd_ttl = ttl - 1; @@ -2625,8 +2664,15 @@ static enum _relay_advice packet_received(void *user_data, ack_rxed(net, net_src, net_dst, net_seqZero, l_get_be32(msg + 3)); + } else if (net_segmented) { + seg_rxed(net, false, iv_index, net_ttl, + net_seq, net_idx, net_src, + net_dst, net_ctl, net_opcode, + key_aid, net_szmic, net_seqZero, + net_segO, net_segN, + msg, app_msg_len); } else { - ctl_received(net, net_key_id, iv_index, net_ttl, + ctl_rxed(net, net_key_id, iv_index, net_ttl, net_seq, net_src, net_dst, net_opcode, rssi, msg, app_msg_len); @@ -2651,8 +2697,9 @@ static enum _relay_advice packet_received(void *user_data, } else { seg_rxed(net, false, iv_index, net_ttl, net_seq, net_idx, net_src, - net_dst, key_aid, net_szmic, - net_seqZero, net_segO, net_segN, + net_dst, net_ctl, net_opcode, + key_aid, net_szmic, net_seqZero, + net_segO, net_segN, msg, app_msg_len); } @@ -3371,16 +3418,16 @@ static bool send_seg(struct mesh_net *net, uint8_t cnt, uint16_t interval, uint8_t gatt_data[30]; uint8_t *packet = gatt_data; uint8_t packet_len; - uint8_t segN = SEG_MAX(msg->segmented, msg->len); - uint16_t seg_off = SEG_OFF(segO); + uint8_t segN = SEG_MAX(msg->ctl, msg->segmented, msg->len); + uint16_t seg_off = SEG_OFF(msg->ctl, segO); uint32_t seq_num; if (msg->segmented) { /* Send each segment on unique seq_num */ seq_num = mesh_net_next_seq_num(net); - if (msg->len - seg_off > SEG_OFF(1)) - seg_len = SEG_OFF(1); + if (msg->len - seg_off > SEG_OFF(msg->ctl, 1)) + seg_len = SEG_OFF(msg->ctl, 1); else seg_len = msg->len - seg_off; } else { @@ -3396,12 +3443,12 @@ static bool send_seg(struct mesh_net *net, uint8_t cnt, uint16_t interval, l_debug("segN %d segment %d seg_off %d", segN, segO, seg_off); /* TODO: Are we RXing on an LPN's behalf? Then set RLY bit */ - if (!mesh_crypto_packet_build(false, msg->ttl, seq_num, msg->src, - msg->remote, 0, msg->segmented, - msg->key_aid, msg->szmic, false, - msg->seqZero, segO, segN, - msg->buf + seg_off, seg_len, - packet + 1, &packet_len)) { + if (!mesh_crypto_packet_build(msg->ctl, msg->ttl, seq_num, msg->src, + msg->remote, msg->opcode, + msg->segmented, msg->key_aid, + msg->szmic, false, msg->seqZero, + segO, segN, msg->buf + seg_off, + seg_len, packet + 1, &packet_len)) { l_error("Failed to build packet"); return false; } @@ -3424,6 +3471,63 @@ static bool send_seg(struct mesh_net *net, uint8_t cnt, uint16_t interval, return true; } +static bool mesh_net_send(struct mesh_net *net, struct mesh_sar *payload, + uint8_t segN) +{ + bool result = false; + + if (payload->segmented) { + struct mesh_sar_tx *drop_sar_tx; + + payload->flags = 0xffffffff >> (31 - segN); + payload->seqZero = payload->seqAuth & SEQ_ZERO_MASK; + + /* Single thread SAR messages to same Unicast DST */ + drop_sar_tx = l_queue_find(net->sar_out, match_sar_tx_remote, + L_UINT_TO_PTR(payload->remote)); + if (drop_sar_tx) { + /* Cancel incomplete prior SAR on the same dst */ + l_debug("Cancel incompleted SAR: SeqZero %4.4x", + drop_sar_tx->sar->seqZero); + l_queue_remove(net->sar_out, drop_sar_tx); + mesh_sar_tx_free(drop_sar_tx); + } + } + + result = send_seg(net, net->tx_cnt, net->tx_interval, payload, 0); + + /* + * Set the timeout to send the next seg or retransmit if the payload is + * segmented. Flush if it is not segmented or if the transmission + * failed. + */ + if (result && payload->segmented) { + struct mesh_sar_tx *sar_tx = mesh_sar_tx_new(); + bool is_unicast = IS_UNICAST(payload->remote); + + sar_tx->ack_received = false; + sar_tx->int_ms = sar_tx_seg_int_ms(net->sar_txr); + sar_tx->attempt_left = sar_tx_retrans_cnt(net->sar_txr, + is_unicast, false); + sar_tx->attempt_left_no_progress = sar_tx_retrans_cnt( + net->sar_txr, + is_unicast, true); + sar_tx->retrans_ms = sar_tx_retrans_timeout_ms(net->sar_txr, + is_unicast, + payload->ttl); + sar_tx->sar = payload; + l_queue_push_head(net->sar_out, sar_tx); + sar_tx->seg_timeout = l_timeout_create_ms(sar_tx->int_ms, + send_next_seg_to, net, NULL); + sar_tx->segO = 1; /* The 0th seg is already sent. */ + sar_tx->segN = segN; + } else { + mesh_sar_free(payload); + } + + return result; +} + void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id, uint32_t iv_index, uint8_t ttl, uint32_t seq, uint16_t src, uint16_t dst, uint32_t hdr, @@ -3497,7 +3601,7 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, /* Long and sizmic messages *require* segmenting */ segmented |= szmic; - seg_max = SEG_MAX(segmented, msg_len); + seg_max = SEG_MAX(false, segmented, msg_len); segmented |= !!(seg_max); /* First enqueue to any Friends and internal models */ @@ -3524,6 +3628,7 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, payload = mesh_sar_new(msg_len); memcpy(payload->buf, msg, msg_len); payload->len = msg_len; + payload->ctl = false; payload->src = src; payload->remote = dst; payload->ttl = ttl; @@ -3535,53 +3640,7 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, payload->seqAuth = seq; payload->segmented = segmented; - if (segmented) { - struct mesh_sar_tx *drop_sar_tx; - payload->flags = 0xffffffff >> (31 - seg_max); - payload->seqZero = seq & SEQ_ZERO_MASK; - - /* Single thread SAR messages to same Unicast DST */ - drop_sar_tx = l_queue_find(net->sar_out, match_sar_tx_remote, - L_UINT_TO_PTR(dst)); - if (drop_sar_tx) { - /* Cancel incomplete prior SAR on the same dst */ - l_debug("Cancel incompleted SAR: SeqZero %4.4x", - drop_sar_tx->sar->seqZero); - l_queue_remove(net->sar_out, drop_sar_tx); - mesh_sar_tx_free(drop_sar_tx); - } - } - - result = send_seg(net, cnt, interval, payload, 0); - - /* - * Set the timeout to send the next seg or retransmit if the payload is - * segmented. Flush if it is not segmented or if the transmission - * failed. - */ - if (result && segmented) { - struct mesh_sar_tx *sar_tx = mesh_sar_tx_new(); - bool is_unicast = IS_UNICAST(dst); - - sar_tx->ack_received = false; - sar_tx->int_ms = sar_tx_seg_int_ms(net->sar_txr); - sar_tx->attempt_left = sar_tx_retrans_cnt(net->sar_txr, - is_unicast, false); - sar_tx->attempt_left_no_progress = sar_tx_retrans_cnt( - net->sar_txr, - is_unicast, true); - sar_tx->retrans_ms = sar_tx_retrans_timeout_ms(net->sar_txr, - is_unicast, - ttl); - sar_tx->sar = payload; - l_queue_push_head(net->sar_out, sar_tx); - sar_tx->seg_timeout = l_timeout_create_ms(sar_tx->int_ms, - send_next_seg_to, net, NULL); - sar_tx->segO = 1; /* The 0th seg is already sent. */ - sar_tx->segN = seg_max; - } else { - mesh_sar_free(payload); - } + result = mesh_net_send(net, payload, seg_max); return result; } @@ -3640,11 +3699,18 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t net_key_id, uint16_t dst, const uint8_t *msg, uint16_t msg_len) { - uint32_t use_seq = seq; - uint8_t pkt_len; - uint8_t pkt[30]; + struct mesh_sar *payload; + uint8_t opcode, seg_max; + bool segmented = false; bool result = false; + /* + * Check maximum message length: + * Parameter length(8) * Maximum # of segments(32) + Header size(1) + */ + if (!net || msg_len > 257) + return; + if (!net->src_addr) return; @@ -3657,10 +3723,19 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t net_key_id, if (ttl == DEFAULT_TTL) ttl = net->default_ttl; - /* Range check the Opcode and msg length*/ - if (*msg & 0xc0 || (9 + msg_len + 8 > 29)) + /* + * Mesh Protocol v1.1: An unassigned address shall not be used in the + * SRC field or the DST field of a Network PDU. + */ + if (IS_UNASSIGNED(src) || IS_UNASSIGNED(dst)) return; + segmented |= msg[0] & SEGMENTED; + seg_max = SEG_MAX(true, segmented, msg_len - 1); + segmented |= !!(seg_max); + + opcode = msg[0] & OPCODE_MASK; + /* * MshPRFv1.0.1 section 3.4.5.2, Interface output filter: * If TTL is set to 1, message shall be dropped. @@ -3681,36 +3756,38 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t net_key_id, /* Deliver to Local entities if applicable */ if (!(dst & 0x8000) && src >= net->src_addr && src <= net->last_addr) - result = ctl_received(net, net_key_id, iv_index, ttl, + result = ctl_rxed(net, net_key_id, iv_index, ttl, mesh_net_next_seq_num(net), src, dst, msg[0], 0, msg + 1, msg_len - 1); if (!net_key_id) { + seq = mesh_net_next_seq_num(net); + + if (result || (dst >= net->src_addr && dst <= net->last_addr)) + return; + } else { struct mesh_subnet *subnet = l_queue_find(net->subnets, - match_key_index, L_UINT_TO_PTR(net_idx)); + match_key_id, L_UINT_TO_PTR(net_key_id)); if (!subnet) return; - net_key_id = subnet->net_key_tx; - use_seq = mesh_net_next_seq_num(net); - - if (result || (dst >= net->src_addr && dst <= net->last_addr)) - return; + net_idx = subnet->idx; } - if (!mesh_crypto_packet_build(true, ttl, use_seq, src, dst, msg[0], - false, 0, false, false, 0, 0, 0, msg + 1, - msg_len - 1, pkt + 1, &pkt_len)) - return; - - if (!net_key_encrypt(net_key_id, iv_index, pkt + 1, pkt_len)) { - l_error("Failed to encode packet"); - return; - } + payload = mesh_sar_new(msg_len - 1); + memcpy(payload->buf, msg + 1, msg_len - 1); + payload->len = msg_len - 1; + payload->ctl = true; + payload->ttl = ttl; + payload->src = src; + payload->remote = dst; + payload->opcode = opcode; + payload->net_idx = net_idx; + payload->iv_index = iv_index; + payload->seqAuth = seq; + payload->segmented = segmented; - if (!(IS_UNASSIGNED(dst))) - send_msg_pkt(net, net->tx_cnt, net->tx_interval, pkt, - pkt_len + 1); + mesh_net_send(net, payload, seg_max); } int mesh_net_key_refresh_phase_set(struct mesh_net *net, uint16_t idx, diff --git a/mesh/net.h b/mesh/net.h index d385ba16e..285c8e355 100644 --- a/mesh/net.h +++ b/mesh/net.h @@ -26,13 +26,32 @@ struct mesh_node; #define KEY_CACHE_SIZE 64 #define FRND_CACHE_MAX 32 -#define MAX_UNSEG_LEN 15 /* msg_len == 11 + sizeof(MIC) */ -#define MAX_SEG_LEN 12 /* UnSeg length - 3 octets overhead */ -#define SEG_MAX(seg, len) ((!seg && len <= MAX_UNSEG_LEN) ? 0 : \ - (((len) - 1) / MAX_SEG_LEN)) - -#define SEG_OFF(seg) ((seg) * MAX_SEG_LEN) -#define MAX_SEG_TO_LEN(seg) ((seg) ? SEG_OFF((seg) + 1) : MAX_UNSEG_LEN) +#define MAX_CTL_UNSEG_LEN 11 /* msg_len == 7 + sizeof(MIC) */ +#define MAX_CTL_SEG_LEN 8 /* UnSeg length - 3 octets overhead */ +#define CTL_SEG_MAX(seg, len) ((!(seg) && (len) <= MAX_CTL_UNSEG_LEN) ? 0 : \ + (((len) - 1) / MAX_CTL_SEG_LEN)) + +#define MAX_ACC_UNSEG_LEN 15 /* msg_len == 11 + sizeof(MIC) */ +#define MAX_ACC_SEG_LEN 12 /* UnSeg length - 3 octets overhead */ +#define ACC_SEG_MAX(seg, len) ((!(seg) && (len) <= MAX_ACC_UNSEG_LEN) ? 0 : \ + (((len) - 1) / MAX_ACC_SEG_LEN)) + +#define MAX_UNSEG_LEN(ctl) ((ctl) ? MAX_CTL_UNSEG_LEN : MAX_ACC_UNSEG_LEN) +#define MAX_SEG_LEN(ctl) ((ctl) ? MAX_CTL_SEG_LEN : MAX_ACC_SEG_LEN) +#define SEG_MAX(ctl, seg, len) ((ctl) ? CTL_SEG_MAX((seg), (len)) : \ + ACC_SEG_MAX((seg), (len))) + +#define CTL_SEG_OFF(seg) ((seg) * MAX_CTL_SEG_LEN) +#define MAX_CTL_SEG_TO_LEN(seg) ((seg) ? CTL_SEG_OFF((seg) + 1) : \ + MAX_CTL_UNSEG_LEN) + +#define ACC_SEG_OFF(seg) ((seg) * MAX_ACC_SEG_LEN) +#define MAX_ACC_SEG_TO_LEN(seg) ((seg) ? ACC_SEG_OFF((seg) + 1) : \ + MAX_ACC_UNSEG_LEN) + +#define SEG_OFF(ctl, seg) ((ctl) ? CTL_SEG_OFF(seg) : ACC_SEG_OFF(seg)) +#define MAX_SEG_TO_LEN(ctl, seg) ((ctl) ? MAX_CTL_SEG_TO_LEN(seg) : \ + MAX_ACC_SEG_TO_LEN(seg)) #define SEGMENTED 0x80 #define UNSEGMENTED 0x00 diff --git a/unit/test-mesh-crypto.c b/unit/test-mesh-crypto.c index 39632d973..56cf8c8e7 100644 --- a/unit/test-mesh-crypto.c +++ b/unit/test-mesh-crypto.c @@ -1087,7 +1087,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) app_msg = l_util_from_hexstring(keys->app_msg, &app_msg_len); if (keys->szmic) { - seg_max = SEG_MAX(keys->segmented, app_msg_len + 8); + seg_max = SEG_MAX(false, keys->segmented, app_msg_len + 8); enc_msg = l_malloc(app_msg_len + 8); status = mesh_crypto_payload_encrypt(aad, app_msg, @@ -1097,7 +1097,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) keys->szmic, keys->akf ? app_key : dev_key); } else { - seg_max = SEG_MAX(keys->segmented, app_msg_len + 4); + seg_max = SEG_MAX(false, keys->segmented, app_msg_len + 4); enc_msg = l_malloc(app_msg_len + 4); status = mesh_crypto_payload_encrypt(aad, app_msg,