[Linuxptp-devel] [PATCH RFC v3 08/10] Implement the ALTERNATE_TIME_OFFSET_ENABLE management message
PTP IEEE 1588 stack for Linux
                
                Brought to you by:
                
                    rcochran
                    
                
            
            
        
        
        
    | 
      
      
      From: Richard C. <ric...@gm...> - 2021-11-09 20:12:14
      
     | 
| If the local PTP management client enables a time zone, append the
matching TLV to outgoing Announce messages.
Signed-off-by: Richard Cochran <ric...@gm...>
---
 clock.c      | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 clock.h      |  8 ++++++
 pmc.c        |  8 ++++++
 pmc_common.c | 17 +++++++++++-
 port.c       |  3 ++
 5 files changed, 110 insertions(+), 3 deletions(-)
diff --git a/clock.c b/clock.c
index 5460c06..9ad418d 100644
--- a/clock.c
+++ b/clock.c
@@ -156,6 +156,40 @@ static int clock_resize_pollfd(struct clock *c, int new_nports);
 static void clock_remove_port(struct clock *c, struct port *p);
 static void clock_stats_display(struct clock_stats *s);
 
+static int clock_alttime_offset_append(struct clock *c, int key, struct ptp_message *m)
+{
+	struct alternate_time_offset_indicator_tlv *atoi;
+	struct tlv_extra *extra;
+	int tlv_len;
+
+	tlv_len = sizeof(*atoi) + c->tz[key].display_name.length;
+	if (tlv_len % 2) {
+		tlv_len++;
+	}
+	extra = msg_tlv_append(m, tlv_len);
+	if (!extra) {
+		return -1;
+	}
+	atoi = (struct alternate_time_offset_indicator_tlv *) extra->tlv;
+	atoi->type = TLV_ALTERNATE_TIME_OFFSET_INDICATOR;
+	atoi->length = tlv_len - sizeof(atoi->type) - sizeof(atoi->length);
+	atoi->keyField = key;
+
+	/* Message alignment broken by design. */
+	memcpy(&atoi->currentOffset, &c->tz[key].current_offset,
+	       sizeof(atoi->currentOffset));
+
+	memcpy(&atoi->jumpSeconds, &c->tz[key].jump_seconds,
+	       sizeof(atoi->jumpSeconds));
+
+	memcpy(&atoi->timeOfNextJump.seconds_lsb, &c->tz[key].next_jump,
+	       sizeof(atoi->timeOfNextJump.seconds_lsb));
+
+	ptp_text_copy(&atoi->displayName, &c->tz[key].display_name);
+
+	return 0;
+}
+
 uint8_t clock_alttime_offset_get_key(struct ptp_message *req)
 {
 	struct management_tlv_datum *mtd;
@@ -461,6 +495,16 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
 		mtd->val = c->tds.flags & PTP_TIMESCALE;
 		datalen = sizeof(*mtd);
 		break;
+	case MID_ALTERNATE_TIME_OFFSET_ENABLE:
+		key = clock_alttime_offset_get_key(req);
+		if (key >= MAX_TIME_ZONES) {
+			break;
+		}
+		mtd = (struct management_tlv_datum *) tlv->data;
+		mtd->val = key;
+		mtd->reserved = c->tz[key].enabled ? 1 : 0;
+		datalen = sizeof(*mtd);
+		break;
 	case MID_ALTERNATE_TIME_OFFSET_NAME:
 		key = clock_alttime_offset_get_key(req);
 		if (key >= MAX_TIME_ZONES) {
@@ -571,7 +615,7 @@ static int clock_management_set(struct clock *c, struct port *p,
 	struct management_tlv_datum *mtd;
 	struct subscribe_events_np *sen;
 	struct management_tlv *tlv;
-	int key, respond = 0;
+	int k, key, respond = 0;
 
 	tlv = (struct management_tlv *) req->management.suffix;
 
@@ -588,6 +632,20 @@ static int clock_management_set(struct clock *c, struct port *p,
 		*changed = 1;
 		respond = 1;
 		break;
+	case MID_ALTERNATE_TIME_OFFSET_ENABLE:
+		mtd = (struct management_tlv_datum *) tlv->data;
+		key = mtd->val;
+		if (key == 0xff) {
+			for (k = 0; k < MAX_TIME_ZONES; k++) {
+				c->tz[k].enabled = mtd->reserved & 1 ? true : false;
+			}
+			respond = 1;
+		}
+		if (key < MAX_TIME_ZONES) {
+			c->tz[key].enabled = mtd->reserved & 1 ? true : false;
+			respond = 1;
+		}
+		break;
 	case MID_ALTERNATE_TIME_OFFSET_NAME:
 		aton = (struct alternate_time_offset_name *) tlv->data;
 		key = aton->keyField;
@@ -889,6 +947,22 @@ static int forwarding(struct clock *c, struct port *p)
 
 /* public methods */
 
+int clock_append_timezones(struct clock *c, struct ptp_message *m)
+{
+	int err = 0, i;
+
+	for (i = 0; i < MAX_TIME_ZONES; i++) {
+		if (!c->tz[i].enabled) {
+			continue;
+		}
+		err = clock_alttime_offset_append(c, i, m);
+		if (err) {
+			break;
+		}
+	}
+	return err;
+}
+
 UInteger8 clock_class(struct clock *c)
 {
 	return c->dds.clockQuality.clockClass;
@@ -1605,7 +1679,6 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
 	case MID_GRANDMASTER_CLUSTER_TABLE:
 	case MID_ACCEPTABLE_MASTER_TABLE:
 	case MID_ACCEPTABLE_MASTER_MAX_TABLE_SIZE:
-	case MID_ALTERNATE_TIME_OFFSET_ENABLE:
 	case MID_ALTERNATE_TIME_OFFSET_MAX_KEY:
 	case MID_TRANSPARENT_CLOCK_DEFAULT_DATA_SET:
 	case MID_PRIMARY_DOMAIN:
diff --git a/clock.h b/clock.h
index 0534f21..ce9ae91 100644
--- a/clock.h
+++ b/clock.h
@@ -43,6 +43,14 @@ enum clock_type {
 	CLOCK_TYPE_MANAGEMENT = 0x0800,
 };
 
+/**
+ * Appends the active time zone TLVs to a given message.
+ * @param c          The clock instance.
+ * @param m          The message that will receive the TLVs.
+ * @return           Zero on success, non-zero otherwise.
+ */
+int clock_append_timezones(struct clock *c, struct ptp_message *m);
+
 /**
  * Obtains a reference to the best foreign master of a clock.
  * @param c  The clock instance.
diff --git a/pmc.c b/pmc.c
index 3f90236..7c711d4 100644
--- a/pmc.c
+++ b/pmc.c
@@ -338,6 +338,14 @@ static void pmc_show(struct ptp_message *msg, FILE *fp)
 		fprintf(fp, "TIMESCALE_PROPERTIES "
 			IFMT "ptpTimescale %d", mtd->val & PTP_TIMESCALE ? 1 : 0);
 		break;
+	case MID_ALTERNATE_TIME_OFFSET_ENABLE:
+		mtd = (struct management_tlv_datum *) mgt->data;
+		fprintf(fp, "ALTERNATE_TIME_OFFSET_ENABLE "
+			IFMT "keyField       %hhu"
+			IFMT "enable         %d",
+			mtd->val,
+			mtd->reserved & 1 ? 1 : 0);
+		break;
 	case MID_ALTERNATE_TIME_OFFSET_NAME:
 		aton = (struct alternate_time_offset_name *) mgt->data;
 		fprintf(fp, "ALTERNATE_TIME_OFFSET_NAME "
diff --git a/pmc_common.c b/pmc_common.c
index 77d50d4..d811b04 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -102,7 +102,7 @@ struct management_id idtab[] = {
 	{ "GRANDMASTER_CLUSTER_TABLE", MID_GRANDMASTER_CLUSTER_TABLE, not_supported },
 	{ "ACCEPTABLE_MASTER_TABLE", MID_ACCEPTABLE_MASTER_TABLE, not_supported },
 	{ "ACCEPTABLE_MASTER_MAX_TABLE_SIZE", MID_ACCEPTABLE_MASTER_MAX_TABLE_SIZE, not_supported },
-	{ "ALTERNATE_TIME_OFFSET_ENABLE", MID_ALTERNATE_TIME_OFFSET_ENABLE, not_supported },
+	{ "ALTERNATE_TIME_OFFSET_ENABLE", MID_ALTERNATE_TIME_OFFSET_ENABLE, do_set_action },
 	{ "ALTERNATE_TIME_OFFSET_NAME", MID_ALTERNATE_TIME_OFFSET_NAME, do_set_action },
 	{ "ALTERNATE_TIME_OFFSET_MAX_KEY", MID_ALTERNATE_TIME_OFFSET_MAX_KEY, not_supported },
 	{ "ALTERNATE_TIME_OFFSET_PROPERTIES", MID_ALTERNATE_TIME_OFFSET_PROPERTIES, do_set_action },
@@ -159,6 +159,7 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
 	char onoff_time_status[4] = "off";
 	char display_name[11] = {0};
 	uint8_t key;
+	int enable;
 
 	switch (action) {
 	case GET:
@@ -185,6 +186,17 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
 		}
 		pmc_send_set_action(pmc, code, &mtd, sizeof(mtd));
 		break;
+	case MID_ALTERNATE_TIME_OFFSET_ENABLE:
+		cnt = sscanf(str,  " %*s %*s keyField %hhu enable %d",
+			     &mtd.val, &enable);
+		if (cnt != 2) {
+			fprintf(stderr, "%s SET needs 2 values\n",
+				idtab[index].name);
+			break;
+		}
+		mtd.reserved = enable ? 1 : 0;
+		pmc_send_set_action(pmc, code, &mtd, sizeof(mtd));
+		break;
 	case MID_ALTERNATE_TIME_OFFSET_NAME:
 		cnt = sscanf(str, " %*s %*s "
 			     "keyField       %hhu "
@@ -586,6 +598,9 @@ static int pmc_tlv_datalen(struct pmc *pmc, int id)
 	case MID_TIME_STATUS_NP:
 		len += sizeof(struct time_status_np);
 		break;
+	case MID_ALTERNATE_TIME_OFFSET_ENABLE:
+		len += sizeof(struct management_tlv_datum);
+		break;
 	case MID_ALTERNATE_TIME_OFFSET_NAME:
 		len += sizeof(struct alternate_time_offset_name);
 		break;
diff --git a/port.c b/port.c
index d204dab..d046ef6 100644
--- a/port.c
+++ b/port.c
@@ -1562,6 +1562,9 @@ int port_tx_announce(struct port *p, struct address *dst, uint16_t sequence_id)
 	if (ieee_c37_238_append(p, msg)) {
 		pr_err("%s: append power profile failed", p->log_name);
 	}
+	if (clock_append_timezones(p->clock, msg)) {
+		pr_err("%s: append time zones failed", p->log_name);
+	}
 
 	err = port_prepare_and_send(p, msg, TRANS_GENERAL);
 	if (err) {
-- 
2.20.1
 |