lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250512012748.79749-5-damien.riegel@silabs.com>
Date: Sun, 11 May 2025 21:27:37 -0400
From: Damien Riégel <damien.riegel@...abs.com>
To: Andrew Lunn <andrew+netdev@...n.ch>,
        "David S . Miller" <davem@...emloft.net>,
        Eric Dumazet <edumazet@...gle.com>, Jakub Kicinski <kuba@...nel.org>,
        Paolo Abeni <pabeni@...hat.com>, Rob Herring <robh@...nel.org>,
        Krzysztof Kozlowski <krzk+dt@...nel.org>,
        Conor Dooley <conor+dt@...nel.org>,
        Silicon Labs Kernel Team <linux-devel@...abs.com>,
        netdev@...r.kernel.org, devicetree@...r.kernel.org,
        linux-kernel@...r.kernel.org
Subject: [RFC net-next 04/15] net: cpc: add protocol header structure and API

CPC frames are composed of a header and optionally a payload. There are
three main frame types currently supported:
  - DATA for transmitting payload or regular control frames (like ACKs,
    that don't have payload associated with them)
  - SYN for connection sequence
  - RST for disconnection and errors

Add structure and functions to operate on this header. They will be
leveraged in a future commit where the protocol is actually implemented.

Signed-off-by: Damien Riégel <damien.riegel@...abs.com>
---
 drivers/net/cpc/Makefile |   2 +-
 drivers/net/cpc/header.c | 237 +++++++++++++++++++++++++++++++++++++++
 drivers/net/cpc/header.h |  83 ++++++++++++++
 3 files changed, 321 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/cpc/header.c
 create mode 100644 drivers/net/cpc/header.h

diff --git a/drivers/net/cpc/Makefile b/drivers/net/cpc/Makefile
index 673a40db424..81c470012c1 100644
--- a/drivers/net/cpc/Makefile
+++ b/drivers/net/cpc/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
-cpc-y := endpoint.o interface.o main.o
+cpc-y := endpoint.o header.o interface.o main.o
 
 obj-$(CONFIG_CPC)	+= cpc.o
diff --git a/drivers/net/cpc/header.c b/drivers/net/cpc/header.c
new file mode 100644
index 00000000000..9f6d637b5ae
--- /dev/null
+++ b/drivers/net/cpc/header.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025, Silicon Laboratories, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/string.h>
+
+#include "header.h"
+
+#define CPC_CONTROL_TYPE_MASK 0xC0
+#define CPC_CONTROL_ACK_MASK BIT(2)
+
+/**
+ * cpc_header_get_type() - Get the frame type.
+ * @hdr_raw: Raw header.
+ * @type: Reference to a frame type.
+ *
+ * Return: True if the type has been successfully decoded, otherwise false.
+ *         On success, the output parameter type is assigned.
+ */
+bool cpc_header_get_type(const u8 hdr_raw[CPC_HEADER_SIZE], enum cpc_frame_type *type)
+{
+	const struct cpc_header *hdr = (struct cpc_header *)hdr_raw;
+
+	switch (FIELD_GET(CPC_CONTROL_TYPE_MASK, hdr->ctrl)) {
+	case CPC_FRAME_TYPE_DATA:
+		*type = CPC_FRAME_TYPE_DATA;
+		break;
+	case CPC_FRAME_TYPE_SYN:
+		*type = CPC_FRAME_TYPE_SYN;
+		break;
+	case CPC_FRAME_TYPE_RST:
+		*type = CPC_FRAME_TYPE_RST;
+		break;
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * cpc_header_get_ep_id() - Get the endpoint id.
+ * @hdr_raw: Raw header.
+ *
+ * Return: Endpoint id.
+ */
+u8 cpc_header_get_ep_id(const u8 hdr_raw[CPC_HEADER_SIZE])
+{
+	const struct cpc_header *hdr = (struct cpc_header *)hdr_raw;
+
+	return hdr->ep_id;
+}
+
+/**
+ * cpc_header_get_recv_wnd() - Get the receive window.
+ * @hdr_raw: Raw header.
+ *
+ * Return: Receive window.
+ */
+u8 cpc_header_get_recv_wnd(const u8 hdr_raw[CPC_HEADER_SIZE])
+{
+	const struct cpc_header *hdr = (struct cpc_header *)hdr_raw;
+
+	return hdr->recv_wnd;
+}
+
+/**
+ * cpc_header_get_seq() - Get the sequence number.
+ * @hdr_raw: Raw header.
+ *
+ * Return: Sequence number.
+ */
+u8 cpc_header_get_seq(const u8 hdr_raw[CPC_HEADER_SIZE])
+{
+	const struct cpc_header *hdr = (struct cpc_header *)hdr_raw;
+
+	return hdr->seq;
+}
+
+/**
+ * cpc_header_get_ack() - Get the acknowledge number.
+ * @hdr_raw: Raw header.
+ *
+ * Return: Acknowledge number.
+ */
+u8 cpc_header_get_ack(const u8 hdr_raw[CPC_HEADER_SIZE])
+{
+	const struct cpc_header *hdr = (struct cpc_header *)hdr_raw;
+
+	return hdr->ack;
+}
+
+/**
+ * cpc_header_get_req_ack() - Get the request acknowledge frame flag.
+ * @hdr_raw: Raw header.
+ *
+ * Return: Request acknowledge frame flag.
+ */
+bool cpc_header_get_req_ack(const u8 hdr_raw[CPC_HEADER_SIZE])
+{
+	const struct cpc_header *hdr = (struct cpc_header *)hdr_raw;
+
+	return FIELD_GET(CPC_CONTROL_ACK_MASK, hdr->ctrl);
+}
+
+/**
+ * cpc_header_get_mtu() - Get the maximum transmission unit.
+ * @hdr_raw: Raw header.
+ *
+ * Return: Maximum transmission unit.
+ *
+ * Must only be used over a SYN frame.
+ */
+u16 cpc_header_get_mtu(const u8 hdr_raw[CPC_HEADER_SIZE])
+{
+	const struct cpc_header *hdr = (struct cpc_header *)hdr_raw;
+
+	return le16_to_cpu(hdr->syn.mtu);
+}
+
+/**
+ * cpc_header_get_payload_len() - Get the payload length.
+ * @hdr_raw: Raw header.
+ *
+ * Return: Payload length.
+ *
+ * Must only be used over a DATA frame.
+ */
+u16 cpc_header_get_payload_len(const u8 hdr_raw[CPC_HEADER_SIZE])
+{
+	const struct cpc_header *hdr = (struct cpc_header *)hdr_raw;
+
+	return le16_to_cpu(hdr->dat.payload_len);
+}
+
+/**
+ * cpc_header_get_ctrl() - Encode parameters into a control byte.
+ * @type: Frame type.
+ * @req_ack: Frame flag indicating a request to be acknowledged.
+ *
+ * Return: Encoded control byte.
+ */
+u8 cpc_header_get_ctrl(enum cpc_frame_type type, bool req_ack)
+{
+	return FIELD_PREP(CPC_CONTROL_TYPE_MASK, type) |
+	       FIELD_PREP(CPC_CONTROL_ACK_MASK, req_ack);
+}
+
+/**
+ * cpc_header_get_frames_acked_count() - Get frames to be acknowledged.
+ * @seq: Current sequence number of the endpoint.
+ * @ack: Acknowledge number of the received frame.
+ * @ack_pending_count: Amount of frames pending on an acknowledge.
+ *
+ * Return: Frames to be acknowledged.
+ */
+u8 cpc_header_get_frames_acked_count(u8 seq, u8 ack, u8 ack_pending_count)
+{
+	u8 frames_acked_count;
+	u8 ack_range_min;
+	u8 ack_range_max;
+
+	ack_range_min = seq + 1;
+	ack_range_max = seq + ack_pending_count;
+
+	if (!cpc_header_number_in_range(ack_range_min, ack_range_max, ack))
+		return 0;
+
+	/* Find number of frames acknowledged with ACK number. */
+	if (ack > seq) {
+		frames_acked_count = ack - seq;
+	} else {
+		frames_acked_count = 256 - seq;
+		frames_acked_count += ack;
+	}
+
+	return frames_acked_count;
+}
+
+/**
+ * cpc_header_is_syn_ack_valid() - Check if the provided SYN-ACK valid or not.
+ * @seq: Current sequence number of the endpoint.
+ * @ack: Acknowledge number of the received SYN.
+ *
+ * Return: True if valid, otherwise false.
+ */
+bool cpc_header_is_syn_ack_valid(u8 seq, u8 ack)
+{
+	return !!cpc_header_get_frames_acked_count(seq, ack, 1);
+}
+
+/**
+ * cpc_header_number_in_window() - Test if a number is within a window.
+ * @start: Start of the window.
+ * @end: Window size.
+ * @n: Number to be tested.
+ *
+ * Given the start of the window and its size, test if the number is
+ * in the range [start; start + wnd).
+ *
+ * @return True if start <= n <= start + wnd - 1 (modulo 256), otherwise false.
+ */
+bool cpc_header_number_in_window(u8 start, u8 wnd, u8 n)
+{
+	u8 end;
+
+	if (wnd == 0)
+		return false;
+
+	end = start + wnd - 1;
+
+	return cpc_header_number_in_range(start, end, n);
+}
+
+/**
+ * cpc_header_number_in_range() - Test if a number is between start and end (included).
+ * @start: Lowest limit.
+ * @end: Highest limit inclusively.
+ * @n: Number to be tested.
+ *
+ * @return True if start <= n <= end (modulo 256), otherwise false.
+ */
+bool cpc_header_number_in_range(u8 start, u8 end, u8 n)
+{
+	if (end >= start) {
+		if (n < start || n > end)
+			return false;
+	} else {
+		if (n > end && n < start)
+			return false;
+	}
+
+	return true;
+}
diff --git a/drivers/net/cpc/header.h b/drivers/net/cpc/header.h
new file mode 100644
index 00000000000..c85bcaef345
--- /dev/null
+++ b/drivers/net/cpc/header.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2025, Silicon Laboratories, Inc.
+ */
+
+#ifndef __CPC_HEADER_H
+#define __CPC_HEADER_H
+
+#include <linux/compiler_attributes.h>
+#include <linux/types.h>
+
+#define CPC_HEADER_MAX_RX_WINDOW 255
+#define CPC_HEADER_SIZE 8
+
+/**
+ * enum cpc_frame_type - Describes all possible frame types that can
+ * be received or sent.
+ * @CPC_FRAME_TYPE_DATA: Used to send and control application DATA frames.
+ * @CPC_FRAME_TYPE_SYN: Used to initiate an endpoint connection.
+ * @CPC_FRAME_TYPE_RST: Used to reset the endpoint connection and indicate
+ *                      that the endpoint is unavailable.
+ */
+enum cpc_frame_type {
+	CPC_FRAME_TYPE_DATA,
+	CPC_FRAME_TYPE_SYN,
+	CPC_FRAME_TYPE_RST,
+};
+
+/**
+ * struct cpc_header - Representation of the CPC header.
+ * @ctrl: Indicates the frame type [7..6] and frame flags [5..0].
+ *        Currently only the request acknowledge flag is supported.
+ *        This flag indicates if the frame should be acknowledged by
+ *        the remote on reception.
+ * @ep_id: Address of the endpoint the frame is destined to.
+ * @recv_wnd: Indicates to the remote how many reception buffers are
+ *            available so it can determine how many frames it can send.
+ * @seq: Identifies the frame with a number.
+ * @ack: Indicate the sequence number of the next expected frame from
+ *       the remote. When paired with a fast re-transmit flag, it indicates
+ *       the sequence number of the frame in error that should be
+ *       re-transmitted.
+ * @syn.mtu: On a SYN frame, this represents the maximum transmission unit.
+ * @dat.payload_len: On a DATA frame, this indicates the payload length.
+ */
+struct cpc_header {
+	u8 ctrl;
+	u8 ep_id;
+	u8 recv_wnd;
+	u8 seq;
+	u8 ack;
+	union {
+		u8 extension[3];
+		struct __packed {
+			__le16 mtu;
+			u8 reserved;
+		} syn;
+		struct __packed {
+			__le16 payload_len;
+			u8 reserved;
+		} dat;
+		struct __packed {
+			u8 reserved[3];
+		} rst;
+	};
+} __packed;
+
+bool cpc_header_get_type(const u8 hdr_raw[CPC_HEADER_SIZE], enum cpc_frame_type *type);
+u8 cpc_header_get_ep_id(const u8 hdr_raw[CPC_HEADER_SIZE]);
+u8 cpc_header_get_recv_wnd(const u8 hdr_raw[CPC_HEADER_SIZE]);
+u8 cpc_header_get_seq(const u8 hdr_raw[CPC_HEADER_SIZE]);
+u8 cpc_header_get_ack(const u8 hdr_raw[CPC_HEADER_SIZE]);
+bool cpc_header_get_req_ack(const u8 hdr_raw[CPC_HEADER_SIZE]);
+u16 cpc_header_get_mtu(const u8 hdr_raw[CPC_HEADER_SIZE]);
+u16 cpc_header_get_payload_len(const u8 hdr_raw[CPC_HEADER_SIZE]);
+u8 cpc_header_get_ctrl(enum cpc_frame_type type, bool req_ack);
+
+u8 cpc_header_get_frames_acked_count(u8 seq, u8 ack, u8 ack_pending_count);
+bool cpc_header_is_syn_ack_valid(u8 seq, u8 ack);
+bool cpc_header_number_in_window(u8 start, u8 wnd, u8 n);
+bool cpc_header_number_in_range(u8 start, u8 end, u8 n);
+
+#endif
-- 
2.49.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ