Interface used for:
- creation, building and storing new SyncE PDU's for later transmission
- obtain Quality Level TLV and Extended Quality Level TLV from existing
  SyncE PDU's

synce_msg_private.h has constants and structs as defined by Synchronous
Ethernet standard - Recommendation ITU-T G.8264//Y.1364.

Co-developed-by: Anatolii Gerasymenko <anatolii.gerasyme...@intel.com>
Signed-off-by: Anatolii Gerasymenko <anatolii.gerasyme...@intel.com>
Co-developed-by: Michal Michalik <michal.micha...@intel.com>
Signed-off-by: Michal Michalik <michal.micha...@intel.com>
Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalew...@intel.com>
---
v2: updated license headers
v3: rebase patch series

 synce_msg.c         | 259 ++++++++++++++++++++++++++++++++++++++++++++
 synce_msg.h         | 174 +++++++++++++++++++++++++++++
 synce_msg_private.h |  87 +++++++++++++++
 3 files changed, 520 insertions(+)
 create mode 100644 synce_msg.c
 create mode 100644 synce_msg.h
 create mode 100644 synce_msg_private.h

diff --git a/synce_msg.c b/synce_msg.c
new file mode 100644
index 0000000..749a27d
--- /dev/null
+++ b/synce_msg.c
@@ -0,0 +1,259 @@
+/**
+ * @file synce_msg.c
+ * @brief Implements the ESMC message type.
+ * @note SPDX-FileCopyrightText: Copyright 2022 Intel Corporation
+ * @note SPDX-License-Identifier: GPL-2.0+
+ */
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/queue.h>
+
+#include "sk.h"
+#include "print.h"
+#include "address.h"
+#include "synce_msg.h"
+#include "synce_msg_private.h"
+
+static void init_tlvs(struct synce_pdu *pdu)
+{
+       TAILQ_INIT(&pdu->tlv_list);
+}
+
+struct synce_pdu *synce_msg_create(const char *iface)
+{
+       const unsigned char dstMac[] = SYNCE_DEST_MACADDR;
+       const unsigned char ituOui[] = SYNCE_ITUOUI;
+       struct synce_pdu *pdu;
+       struct address srcMac;
+
+       if (sk_interface_macaddr(iface, &srcMac)) {
+               pr_err("mac get failed");
+               return NULL;
+       }
+
+       pdu = (struct synce_pdu *) malloc(sizeof(struct synce_pdu));
+       if (!pdu) {
+               pr_err("memory allocation for Sync-E PDU failed");
+               return NULL;
+       }
+       memset(pdu, 0, sizeof(struct synce_pdu));
+       memcpy(&pdu->header.dstAddr, &dstMac, sizeof(pdu->header.dstAddr));
+       pdu->header.ethertype = htons(ETH_P_SLOW);
+       pdu->header.ethersubtype = SYNCE_ETHERSUBTYPE;
+       memcpy(&pdu->header.ituOui, &ituOui, sizeof(pdu->header.ituOui));
+       pdu->header.ituSubtype = htons(SYNCE_ITUSUBTYPE);
+       pdu->header.verEvtflag = SYNCE_VERSION << SYNCE_VERSION_SHIFT;
+       memset(&pdu->header.reserved, 0, sizeof(pdu->header.reserved));
+       memcpy(&pdu->header.srcAddr, &srcMac.sll.sll_addr,
+              sizeof(pdu->header.srcAddr));
+
+       init_tlvs(pdu);
+
+       return pdu;
+}
+
+void synce_msg_delete(struct synce_pdu *pdu)
+{
+       synce_msg_reset_tlvs(pdu);
+       free(pdu);
+}
+
+static void attach_esmc_tlv(struct synce_pdu *pdu, struct esmc_tlv *tlv)
+{
+       TAILQ_INSERT_TAIL(&pdu->tlv_list, tlv, list);
+}
+
+int synce_msg_get_esmc_tlvs_size(struct synce_pdu *pdu)
+{
+       struct esmc_tlv *tlv;
+       int size = 0;
+
+       TAILQ_FOREACH(tlv, &pdu->tlv_list, list) {
+               size += ntohs(tlv->ql_tlv.length);
+       }
+
+       return size;
+}
+
+static int generate_tlvs(struct synce_pdu *pdu)
+{
+       struct esmc_tlv *tlv;
+       void *cur;
+       int size;
+
+       size = synce_msg_get_esmc_tlvs_size(pdu);
+       if (ETH_DATA_LEN - ETH_FCS_LEN - size < 0) {
+               pr_err("too many tlvs");
+               return -EMSGSIZE;
+       }
+
+       cur = (void *)pdu + sizeof(struct esmc_header);
+       TAILQ_FOREACH(tlv, &pdu->tlv_list, list) {
+               size = ntohs(tlv->ql_tlv.length);
+               memcpy(cur, tlv, size);
+               cur += size;
+       }
+
+       return 0;
+}
+
+int synce_msg_attach_ql_tlv(struct synce_pdu *pdu, uint8_t ssmCode)
+{
+       struct esmc_tlv *tlv;
+
+       if (~QL_TLV_SSM_MASK & ssmCode) {
+               pr_err("4 upper bits of QL TLV ssmCode should not be used");
+               return -EINVAL;
+       }
+
+       tlv = malloc(sizeof(struct esmc_tlv));
+       if (!tlv) {
+               pr_err("malloc failed for TLV: %m");
+               return -EINVAL;
+       }
+
+       tlv->ql_tlv.type = QL_TLV_TYPE;
+       tlv->ql_tlv.length = htons(QL_TLV_LEN);
+       tlv->ql_tlv.ssmCode = ssmCode;
+
+       attach_esmc_tlv(pdu, tlv);
+
+       generate_tlvs(pdu);
+
+       return 0;
+}
+
+int synce_msg_get_ql_tlv(struct synce_pdu *pdu, uint8_t *ssmCode)
+{
+       struct esmc_tlv *tlv;
+
+       if (!pdu || !ssmCode) {
+               return -ENXIO;
+       }
+
+       TAILQ_FOREACH(tlv, &pdu->tlv_list, list) {
+               if (tlv->ql_tlv.type == QL_TLV_TYPE) {
+                       break;
+               }
+       }
+
+       if (!tlv) {
+               return -EAGAIN;
+       }
+
+       *ssmCode = tlv->ql_tlv.ssmCode;
+
+       return 0;
+}
+
+int synce_msg_attach_extended_ql_tlv(struct synce_pdu *pdu,
+                                    struct synce_msg_ext_ql *ext_ql)
+{
+       struct esmc_tlv *tlv;
+
+       if (!pdu || !ext_ql) {
+               pr_err("either pdu or ext_ql not provided");
+               return -ENXIO;
+       }
+
+       tlv = malloc(sizeof(struct esmc_tlv));
+       if (!tlv) {
+               pr_err("malloc failed for TLV: %m");
+               return -ENOMEM;
+       }
+
+       tlv->extended_ql_tlv.type = EXT_QL_TLV_TYPE;
+       tlv->extended_ql_tlv.length = htons(EXT_QL_TLV_LEN);
+       tlv->extended_ql_tlv.enhancedSsmCode = ext_ql->enhancedSsmCode;
+       memcpy(&tlv->extended_ql_tlv.clockIdentity, &ext_ql->clockIdentity,
+              sizeof(tlv->extended_ql_tlv.clockIdentity));
+       tlv->extended_ql_tlv.flag = ext_ql->flag;
+       tlv->extended_ql_tlv.cascaded_eEEcs = ext_ql->cascaded_eEEcs;
+       tlv->extended_ql_tlv.cascaded_EEcs = ext_ql->cascaded_EEcs;
+
+       attach_esmc_tlv(pdu, tlv);
+
+       generate_tlvs(pdu);
+
+       return 0;
+}
+
+int synce_msg_get_extended_ql_tlv(struct synce_pdu *pdu,
+                                 struct synce_msg_ext_ql *ext_ql)
+{
+       struct esmc_tlv *tlv;
+
+       if (!pdu || !ext_ql) {
+               return -ENXIO;
+       }
+
+       TAILQ_FOREACH(tlv, &pdu->tlv_list, list) {
+               if (tlv->ql_tlv.type == EXT_QL_TLV_TYPE) {
+                       break;
+               }
+       }
+
+       if (!tlv) {
+               return -EAGAIN;
+       }
+
+       ext_ql->enhancedSsmCode = tlv->extended_ql_tlv.enhancedSsmCode;
+       memcpy(&ext_ql->clockIdentity, &tlv->extended_ql_tlv.clockIdentity,
+              sizeof(ext_ql->clockIdentity));
+       ext_ql->flag = tlv->extended_ql_tlv.flag;
+       ext_ql->cascaded_eEEcs = tlv->extended_ql_tlv.cascaded_eEEcs;
+       ext_ql->cascaded_EEcs = tlv->extended_ql_tlv.cascaded_EEcs;
+
+       return 0;
+}
+
+void synce_msg_reset_tlvs(struct synce_pdu *pdu)
+{
+       struct esmc_tlv *tlv, *tlv_temp;
+
+       tlv = TAILQ_FIRST(&pdu->tlv_list);
+       while (tlv != NULL) {
+               tlv_temp = TAILQ_NEXT(tlv, list);
+               free(tlv);
+               tlv = tlv_temp;
+       }
+       init_tlvs(pdu);
+}
+
+static bool is_valid_synce_tlv(struct esmc_tlv *tlv)
+{
+       if (tlv->ql_tlv.type == QL_TLV_TYPE &&
+           ntohs(tlv->ql_tlv.length) == QL_TLV_LEN)
+               return true;
+       if (tlv->ql_tlv.type == EXT_QL_TLV_TYPE &&
+           ntohs(tlv->ql_tlv.length) == EXT_QL_TLV_LEN)
+               return true;
+       return false;
+}
+
+void synce_msg_recover_tlvs(struct synce_pdu *pdu)
+{
+       struct esmc_tlv *tlv, *new_tlv;
+
+       if (TAILQ_EMPTY(&pdu->tlv_list)) {
+               init_tlvs(pdu);
+       }
+
+       synce_msg_reset_tlvs(pdu);
+
+       tlv = (struct esmc_tlv *)((void *)pdu + sizeof(struct esmc_header));
+       while (is_valid_synce_tlv(tlv)) {
+               new_tlv = malloc(sizeof(struct esmc_tlv));
+               if (!new_tlv) {
+                       pr_err("allocate new_tlv failed");
+                       return;
+               }
+               memset(new_tlv, 0, sizeof(*new_tlv));
+               /* We copy data from receiving buffer into larger structure. The
+                * TLV size is validated in is_valid_synce_tlv before copying.
+                */
+               memcpy(new_tlv, tlv, ntohs(tlv->ql_tlv.length));
+               TAILQ_INSERT_TAIL(&pdu->tlv_list, new_tlv, list);
+               tlv = (struct esmc_tlv *)((void *)tlv + 
ntohs(tlv->ql_tlv.length));
+       }
+}
diff --git a/synce_msg.h b/synce_msg.h
new file mode 100644
index 0000000..3ab6d9b
--- /dev/null
+++ b/synce_msg.h
@@ -0,0 +1,174 @@
+/**
+ * @file synce_msg.h
+ * @brief Implements the ESMC message type.
+ * @note SPDX-FileCopyrightText: Copyright 2022 Intel Corporation
+ * @note SPDX-License-Identifier: GPL-2.0+
+ */
+#ifndef HAVE_SYNCE_MSG_H
+#define HAVE_SYNCE_MSG_H
+
+#include "ddt.h"
+
+#define SYNCE_NETWORK_OPT_1            1
+#define SYNCE_NETWORK_OPT_2            2
+
+/* Enhanced SSM codes for SyncE */
+#define QL_EEC1_ENHSSM                 0xFF
+#define QL_EEC2_ENHSSM                 0xFF
+#define QL_OTHER_CLOCK_TYPES_ENHSSM    0xFF
+#define QL_PRTC_ENHSSM                 0x20
+#define QL_ePRTC_ENHSSM                        0x21
+#define QL_eEEC_ENHSSM                 0x22
+#define QL_ePRC_ENHSSM                 0x23
+
+/* SSM codes and enhanced SSM codes for SyncE in option 1 networks */
+#define O1N_QL_PRC_SSM                 0x2
+#define O1N_QL_PRC_ENHSSM              0xFF
+#define O1N_QL_SSU_A_SSM               0x4
+#define O1N_QL_SSU_A_ENHSSM            0xFF
+#define O1N_QL_SSU_B_SSM               0x8
+#define O1N_QL_SSU_B_ENHSSM            0xFF
+#define O1N_QL_EEC1_SSM                        0xB
+#define O1N_QL_EEC1_ENHSSM             0xFF
+#define O1N_QL_DNU_SSM                 0xF
+#define O1N_QL_DNU_ENHSSM              0xFF
+#define O1N_QL_PRTC_SSM                        0x2
+#define O1N_QL_PRTC_ENHSSM             0x20
+#define O1N_QL_EPRTC_SSM               0x2
+#define O1N_QL_EPRTC_ENHSSM            0x21
+#define O1N_QL_EEEC_SSM                        0xB
+#define O1N_QL_EEEC_ENHSSM             0x22
+#define O1N_QL_EPRC_SSM                        0x2
+#define O1N_QL_EPRC_ENHSSM             0x23
+
+/* SSM codes and enhanced SSM codes for SyncE in option 2 networks */
+#define O2N_QL_PRS_SSM                 0x1
+#define O2N_QL_PRS_ENHSSM              0xFF
+#define O2N_QL_STU_SSM                 0x0
+#define O2N_QL_STU_ENHSSM              0xFF
+#define O2N_QL_ST2_SSM                 0x7
+#define O2N_QL_ST2_ENHSSM              0xFF
+#define O2N_QL_TNC_SSM                 0x4
+#define O2N_QL_TNC_ENHSSM              0xFF
+#define O2N_QL_ST3E_SSM                        0xD
+#define O2N_QL_ST3E_ENHSSM             0xFF
+#define O2N_QL_ST3_SSM                 0xA
+#define O2N_QL_ST3_ENHSSM              0xFF
+#define O2N_QL_EEC2_SSM                        0xA
+#define O2N_QL_EEC2_ENHSSM             0xFF
+#define O2N_QL_PROV_SSM                        0xE
+#define O2N_QL_PROV_ENHSSM             0xFF
+#define O2N_QL_DUS_SSM                 0xF
+#define O2N_QL_DUS_ENHSSM              0xFF
+#define O2N_QL_PRTC_SSM                        0x1
+#define O2N_QL_PRTC_ENHSSM             0x20
+#define O2N_QL_EPRTC_SSM               0x1
+#define O2N_QL_EPRTC_ENHSSM            0x21
+#define O2N_QL_EEEC_SSM                        0xA
+#define O2N_QL_EEEC_ENHSSM             0x22
+#define O2N_QL_EPRC_SSM                        0x1
+#define O2N_QL_EPRC_ENHSSM             0x23
+
+/* Flags as defined in SyncE specification */
+#define MIXED_EEC_CHAIN_FLAG           (1 << 0)
+#define PARTIAL_EEC_CHAIN_FLAG         (1 << 1)
+
+/* 5 seconds is a period defined by standard for QL-failed state */
+#define QL_FAILED_PERIOD_SEC           5
+
+struct synce_msg_ext_ql {
+       uint8_t enhancedSsmCode;
+       struct ClockIdentity clockIdentity;
+       uint8_t flag;
+       uint8_t cascaded_eEEcs;
+       uint8_t cascaded_EEcs;
+};
+
+/**
+ * Create a ESMC Protocol Data Unit (PDU) template.
+ *
+ * This high level API creates structure for storing ESMC PDU and
+ * initializes TLV vector for conveniently storing and processing
+ * TLV structures (esmc_tlv). All the fields are stored in network
+ * byte ordering.
+ *
+ * @param iface        A name of interface to create prepopulated template for
+ * @return     A pointer to a ESMC Sync-E PDU prepopulated template
+ */
+struct synce_pdu *synce_msg_create(const char *iface);
+
+/**
+ * Delete a ESMC Protocol Data Unit (PDU) from memory.
+ *
+ * This high level API frees all the memory stored in TLV vector and
+ * then free ESMC PDU itself.
+ *
+ * @param pdu  A pointer to a ESMC Sync-E PDU
+ */
+void synce_msg_delete(struct synce_pdu *pdu);
+
+/**
+ * Attach QL TLV to Sync-E PDU.
+ *
+ * @param pdu          A pointer to a ESMC Sync-E PDU
+ * @param ssmCode      SSM Code of newly created QL TLV
+ * @return             Zero on success, non-zero if failure
+ */
+int synce_msg_attach_ql_tlv(struct synce_pdu *pdu, uint8_t ssmCode);
+
+/**
+ * Get QL TLVs SSM Code from Sync-E PDU.
+ *
+ * @param pdu                  A pointer to a ESMC Sync-E PDU
+ * @param ssmCode              SSM Code variable to store
+ * @return                     Zero on success, non-zero if failure
+ */
+int synce_msg_get_ql_tlv(struct synce_pdu *pdu, uint8_t *ssmCode);
+
+/**
+ * Attach Extended QL TLV to Sync-E PDU.
+ *
+ * @param pdu                  A pointer to a ESMC Sync-E PDU
+ * @param enhancedSsmCode      Enhanced SSM Code of newly created QL TLV
+ * @param clockIdentity                SyncE clockIdentity of the originator 
of the extended QL TLV
+ * @param flag                 Flag (see ITU-T G.8264)
+ * @param cascaded_eEEcs               Number of cascaded eEECs from the 
nearest SSU/PRC/ePRC
+ * @param cascaded_EEcs                Number of cascaded EECs from the 
nearest SSU/PRC/ePRC
+ * @return                     Zero on success, non-zero if failure
+ */
+int synce_msg_attach_extended_ql_tlv(struct synce_pdu *pdu,
+                                    struct synce_msg_ext_ql *ext_ql);
+
+/**
+ * Get QL Extended TLVs from Sync-E PDU in.
+ *
+ * @param pdu                  A pointer to a ESMC Sync-E PDU
+ * @param ext_ql                       A pointer to Extended Quality level
+ * @return                     Zero on success, non-zero if failure
+ */
+int synce_msg_get_extended_ql_tlv(struct synce_pdu *pdu,
+                                 struct synce_msg_ext_ql *ext_ql);
+
+/**
+ * Reset (clear and reinitialize) all the TLV vector entries.
+ *
+ * @param pdu  A pointer to a ESMC Sync-E PDU
+ */
+void synce_msg_reset_tlvs(struct synce_pdu *pdu);
+
+/**
+ * Recover TLVs from ESMC frame into TLV vector entries in PDU structure.
+ *
+ * @param pdu  A pointer to a ESMC Sync-E PDU
+ */
+void synce_msg_recover_tlvs(struct synce_pdu *pdu);
+
+/**
+ * Returns the size of TLV vector entries in PDU.
+ *
+ * @param pdu  A pointer to a ESMC Sync-E PDU
+ * @return     Number of bytes of all TLV entries attached to PDU
+ */
+int synce_msg_get_esmc_tlvs_size(struct synce_pdu *pdu);
+
+#endif
diff --git a/synce_msg_private.h b/synce_msg_private.h
new file mode 100644
index 0000000..aa770f3
--- /dev/null
+++ b/synce_msg_private.h
@@ -0,0 +1,87 @@
+/**
+ * @file synce_msg_private.h
+ * @brief Implements the ESMC message private structures.
+ * @note SPDX-FileCopyrightText: Copyright 2022 Intel Corporation
+ * @note SPDX-License-Identifier: GPL-2.0+
+ */
+#ifndef HAVE_SYNCE_MSG_PRIVATE_H
+#define HAVE_SYNCE_MSG_PRIVATE_H
+
+/* Sync-E Frame */
+#define SYNCE_DEST_MACADDR { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 }
+#define SYNCE_ETHERTYPE ETH_P_SLOW
+#define SYNCE_ETHERSUBTYPE 0x0A
+#define SYNCE_ITUOUI { 0x00, 0x19, 0xA7 }
+#define SYNCE_ITUOUI_SIZE 3
+#define SYNCE_ITUSUBTYPE 0x0001
+#define SYNCE_VERSION 1
+#define SYNCE_VERSION_SHIFT 4
+#define SYNCE_EVENT_SHIFT 4
+
+/* QL TLV */
+#define QL_TLV_TYPE 1
+#define QL_TLV_LEN 0x4
+#define QL_TLV_SSM_MASK 0x0f
+#define EXT_QL_TLV_TYPE 2
+#define EXT_QL_TLV_LEN 0x14
+
+#include <errno.h>
+#include <sys/queue.h>
+#include <linux/if_ether.h>
+
+#include "ddt.h"
+#include "ether.h"
+
+struct macaddr {
+       uint8_t addr[MAC_LEN];
+} PACKED;
+
+struct ql_tlv {
+       uint8_t type;
+       uint16_t length;
+       uint8_t ssmCode; /* unused:4 | SSM code:4 */
+} PACKED;
+
+struct extended_ql_tlv {
+       uint8_t type;
+       uint16_t length;
+       uint8_t enhancedSsmCode;
+       struct ClockIdentity clockIdentity;
+       uint8_t flag;
+       uint8_t cascaded_eEEcs;
+       uint8_t cascaded_EEcs;
+       uint8_t reserved[5];
+} PACKED;
+
+struct esmc_tlv {
+       union {
+               struct ql_tlv ql_tlv;
+               struct extended_ql_tlv extended_ql_tlv;
+       };
+       TAILQ_ENTRY(esmc_tlv) list;
+} PACKED;
+
+struct esmc_header {
+       struct macaddr      dstAddr;
+       struct macaddr      srcAddr;
+       uint16_t            ethertype;
+       uint8_t             ethersubtype;
+       uint8_t             ituOui[SYNCE_ITUOUI_SIZE]; /* Organizationally 
Unique Identifier */
+       uint16_t            ituSubtype;
+       uint8_t             verEvtflag; /* version:4 | event flag:1 | 
reserved:3 */
+       uint8_t             reserved[3];
+} PACKED;
+
+struct esmc_data {
+       uint8_t buffer[ETH_DATA_LEN];
+};
+
+struct synce_pdu {
+       union {
+               struct esmc_header header;
+               struct esmc_data data;
+       } PACKED;
+       TAILQ_HEAD(ql_tlv_list, esmc_tlv) tlv_list;
+};
+
+#endif
-- 
2.26.0



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to