2012-08-05 20:14:44 +08:00
|
|
|
/**
|
|
|
|
* @file pmc.c
|
|
|
|
* @brief PTP management client program
|
|
|
|
* @note Copyright (C) 2012 Richard Cochran <richardcochran@gmail.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
#include <errno.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <stdio.h>
|
2012-08-25 15:46:34 +08:00
|
|
|
#include <stdlib.h>
|
2012-08-05 20:14:44 +08:00
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2012-12-18 21:00:49 +08:00
|
|
|
#include <inttypes.h>
|
2013-02-25 07:56:38 +08:00
|
|
|
#include <arpa/inet.h>
|
2012-08-05 20:14:44 +08:00
|
|
|
|
2012-08-25 22:13:23 +08:00
|
|
|
#include "ds.h"
|
2012-12-04 21:36:01 +08:00
|
|
|
#include "fsm.h"
|
2013-01-31 01:31:50 +08:00
|
|
|
#include "pmc_common.h"
|
2012-08-05 20:14:44 +08:00
|
|
|
#include "print.h"
|
|
|
|
#include "tlv.h"
|
2013-09-30 02:58:17 +08:00
|
|
|
#include "uds.h"
|
2012-08-05 20:14:44 +08:00
|
|
|
#include "util.h"
|
2012-12-10 17:28:28 +08:00
|
|
|
#include "version.h"
|
2012-08-05 20:14:44 +08:00
|
|
|
|
|
|
|
#define BAD_ACTION -1
|
|
|
|
#define BAD_ID -1
|
|
|
|
#define AMBIGUOUS_ID -2
|
|
|
|
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
2012-09-12 23:44:20 +08:00
|
|
|
#define P41 ((double)(1ULL << 41))
|
2012-08-05 20:14:44 +08:00
|
|
|
|
2013-01-31 01:31:50 +08:00
|
|
|
static struct pmc *pmc;
|
2012-08-05 20:14:44 +08:00
|
|
|
|
2013-07-06 20:00:43 +08:00
|
|
|
static void do_get_action(int action, int index, char *str);
|
|
|
|
static void do_set_action(int action, int index, char *str);
|
|
|
|
static void not_supported(int action, int index, char *str);
|
|
|
|
static void null_management(int action, int index, char *str);
|
2012-08-05 20:14:44 +08:00
|
|
|
|
|
|
|
struct management_id {
|
|
|
|
char name[64];
|
|
|
|
int code;
|
2013-07-06 20:00:43 +08:00
|
|
|
void (*func)(int action, int index, char *str);
|
2012-08-05 20:14:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct management_id idtab[] = {
|
|
|
|
/* Clock management ID values */
|
2014-06-25 18:45:23 +08:00
|
|
|
{ "USER_DESCRIPTION", TLV_USER_DESCRIPTION, do_get_action },
|
|
|
|
{ "SAVE_IN_NON_VOLATILE_STORAGE", TLV_SAVE_IN_NON_VOLATILE_STORAGE, not_supported },
|
|
|
|
{ "RESET_NON_VOLATILE_STORAGE", TLV_RESET_NON_VOLATILE_STORAGE, not_supported },
|
|
|
|
{ "INITIALIZE", TLV_INITIALIZE, not_supported },
|
|
|
|
{ "FAULT_LOG", TLV_FAULT_LOG, not_supported },
|
|
|
|
{ "FAULT_LOG_RESET", TLV_FAULT_LOG_RESET, not_supported },
|
|
|
|
{ "DEFAULT_DATA_SET", TLV_DEFAULT_DATA_SET, do_get_action },
|
|
|
|
{ "CURRENT_DATA_SET", TLV_CURRENT_DATA_SET, do_get_action },
|
|
|
|
{ "PARENT_DATA_SET", TLV_PARENT_DATA_SET, do_get_action },
|
|
|
|
{ "TIME_PROPERTIES_DATA_SET", TLV_TIME_PROPERTIES_DATA_SET, do_get_action },
|
2015-03-18 03:10:33 +08:00
|
|
|
{ "PRIORITY1", TLV_PRIORITY1, do_set_action },
|
|
|
|
{ "PRIORITY2", TLV_PRIORITY2, do_set_action },
|
2014-06-25 18:45:23 +08:00
|
|
|
{ "DOMAIN", TLV_DOMAIN, do_get_action },
|
|
|
|
{ "SLAVE_ONLY", TLV_SLAVE_ONLY, do_get_action },
|
|
|
|
{ "TIME", TLV_TIME, not_supported },
|
|
|
|
{ "CLOCK_ACCURACY", TLV_CLOCK_ACCURACY, do_get_action },
|
|
|
|
{ "UTC_PROPERTIES", TLV_UTC_PROPERTIES, not_supported },
|
|
|
|
{ "TRACEABILITY_PROPERTIES", TLV_TRACEABILITY_PROPERTIES, do_get_action },
|
|
|
|
{ "TIMESCALE_PROPERTIES", TLV_TIMESCALE_PROPERTIES, do_get_action },
|
|
|
|
{ "PATH_TRACE_LIST", TLV_PATH_TRACE_LIST, not_supported },
|
|
|
|
{ "PATH_TRACE_ENABLE", TLV_PATH_TRACE_ENABLE, not_supported },
|
|
|
|
{ "GRANDMASTER_CLUSTER_TABLE", TLV_GRANDMASTER_CLUSTER_TABLE, not_supported },
|
|
|
|
{ "ACCEPTABLE_MASTER_TABLE", TLV_ACCEPTABLE_MASTER_TABLE, not_supported },
|
|
|
|
{ "ACCEPTABLE_MASTER_MAX_TABLE_SIZE", TLV_ACCEPTABLE_MASTER_MAX_TABLE_SIZE, not_supported },
|
|
|
|
{ "ALTERNATE_TIME_OFFSET_ENABLE", TLV_ALTERNATE_TIME_OFFSET_ENABLE, not_supported },
|
|
|
|
{ "ALTERNATE_TIME_OFFSET_NAME", TLV_ALTERNATE_TIME_OFFSET_NAME, not_supported },
|
|
|
|
{ "ALTERNATE_TIME_OFFSET_MAX_KEY", TLV_ALTERNATE_TIME_OFFSET_MAX_KEY, not_supported },
|
|
|
|
{ "ALTERNATE_TIME_OFFSET_PROPERTIES", TLV_ALTERNATE_TIME_OFFSET_PROPERTIES, not_supported },
|
|
|
|
{ "TRANSPARENT_CLOCK_DEFAULT_DATA_SET", TLV_TRANSPARENT_CLOCK_DEFAULT_DATA_SET, not_supported },
|
|
|
|
{ "PRIMARY_DOMAIN", TLV_PRIMARY_DOMAIN, not_supported },
|
|
|
|
{ "TIME_STATUS_NP", TLV_TIME_STATUS_NP, do_get_action },
|
|
|
|
{ "GRANDMASTER_SETTINGS_NP", TLV_GRANDMASTER_SETTINGS_NP, do_set_action },
|
2012-08-05 20:14:44 +08:00
|
|
|
/* Port management ID values */
|
2014-06-25 18:45:23 +08:00
|
|
|
{ "NULL_MANAGEMENT", TLV_NULL_MANAGEMENT, null_management },
|
|
|
|
{ "CLOCK_DESCRIPTION", TLV_CLOCK_DESCRIPTION, do_get_action },
|
|
|
|
{ "PORT_DATA_SET", TLV_PORT_DATA_SET, do_get_action },
|
|
|
|
{ "LOG_ANNOUNCE_INTERVAL", TLV_LOG_ANNOUNCE_INTERVAL, do_get_action },
|
|
|
|
{ "ANNOUNCE_RECEIPT_TIMEOUT", TLV_ANNOUNCE_RECEIPT_TIMEOUT, do_get_action },
|
|
|
|
{ "LOG_SYNC_INTERVAL", TLV_LOG_SYNC_INTERVAL, do_get_action },
|
|
|
|
{ "VERSION_NUMBER", TLV_VERSION_NUMBER, do_get_action },
|
|
|
|
{ "ENABLE_PORT", TLV_ENABLE_PORT, not_supported },
|
|
|
|
{ "DISABLE_PORT", TLV_DISABLE_PORT, not_supported },
|
|
|
|
{ "UNICAST_NEGOTIATION_ENABLE", TLV_UNICAST_NEGOTIATION_ENABLE, not_supported },
|
|
|
|
{ "UNICAST_MASTER_TABLE", TLV_UNICAST_MASTER_TABLE, not_supported },
|
|
|
|
{ "UNICAST_MASTER_MAX_TABLE_SIZE", TLV_UNICAST_MASTER_MAX_TABLE_SIZE, not_supported },
|
|
|
|
{ "ACCEPTABLE_MASTER_TABLE_ENABLED", TLV_ACCEPTABLE_MASTER_TABLE_ENABLED, not_supported },
|
|
|
|
{ "ALTERNATE_MASTER", TLV_ALTERNATE_MASTER, not_supported },
|
|
|
|
{ "TRANSPARENT_CLOCK_PORT_DATA_SET", TLV_TRANSPARENT_CLOCK_PORT_DATA_SET, not_supported },
|
|
|
|
{ "DELAY_MECHANISM", TLV_DELAY_MECHANISM, do_get_action },
|
|
|
|
{ "LOG_MIN_PDELAY_REQ_INTERVAL", TLV_LOG_MIN_PDELAY_REQ_INTERVAL, do_get_action },
|
|
|
|
{ "PORT_DATA_SET_NP", TLV_PORT_DATA_SET_NP, do_set_action },
|
2012-08-05 20:14:44 +08:00
|
|
|
};
|
|
|
|
|
2014-02-08 00:52:03 +08:00
|
|
|
static const char *action_string[] = {
|
2012-08-05 20:14:44 +08:00
|
|
|
"GET",
|
|
|
|
"SET",
|
|
|
|
"RESPONSE",
|
|
|
|
"COMMAND",
|
|
|
|
"ACKNOWLEDGE",
|
|
|
|
};
|
|
|
|
|
2012-08-22 21:49:04 +08:00
|
|
|
#define IFMT "\n\t\t"
|
|
|
|
|
2013-07-06 17:28:56 +08:00
|
|
|
static char *text2str(struct PTPText *text)
|
|
|
|
{
|
2013-02-25 07:56:38 +08:00
|
|
|
static struct static_ptp_text s;
|
|
|
|
s.max_symbols = -1;
|
|
|
|
static_ptp_text_copy(&s, text);
|
|
|
|
return (char*)(s.text);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_PRINT_BYTES 16
|
|
|
|
#define BIN_BUF_SIZE (MAX_PRINT_BYTES * 3 + 1)
|
|
|
|
|
2013-07-06 17:28:56 +08:00
|
|
|
static char *bin2str_impl(Octet *data, int len, char *buf, int buf_len)
|
|
|
|
{
|
2013-02-25 07:56:38 +08:00
|
|
|
int i, offset = 0;
|
|
|
|
if (len > MAX_PRINT_BYTES)
|
|
|
|
len = MAX_PRINT_BYTES;
|
|
|
|
buf[0] = '\0';
|
2013-03-12 05:29:18 +08:00
|
|
|
if (!data)
|
|
|
|
return buf;
|
2013-02-25 07:56:38 +08:00
|
|
|
if (len)
|
|
|
|
offset += snprintf(buf, buf_len, "%02hhx", data[0]);
|
|
|
|
for (i = 1; i < len; i++) {
|
|
|
|
if (offset >= buf_len)
|
|
|
|
/* truncated output */
|
|
|
|
break;
|
|
|
|
offset += snprintf(buf + offset, buf_len - offset, ":%02hhx", data[i]);
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2013-07-06 17:28:56 +08:00
|
|
|
static char *bin2str(Octet *data, int len)
|
|
|
|
{
|
2013-02-25 07:56:38 +08:00
|
|
|
static char buf[BIN_BUF_SIZE];
|
|
|
|
return bin2str_impl(data, len, buf, sizeof(buf));
|
|
|
|
}
|
|
|
|
|
2013-07-06 17:28:56 +08:00
|
|
|
static uint16_t align16(uint16_t *p)
|
|
|
|
{
|
2013-02-25 07:56:38 +08:00
|
|
|
uint16_t v;
|
|
|
|
memcpy(&v, p, sizeof(v));
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2013-07-06 17:28:56 +08:00
|
|
|
static char *portaddr2str(struct PortAddress *addr)
|
|
|
|
{
|
2013-02-25 07:56:38 +08:00
|
|
|
static char buf[BIN_BUF_SIZE];
|
|
|
|
switch(align16(&addr->networkProtocol)) {
|
|
|
|
case TRANS_UDP_IPV4:
|
|
|
|
if (align16(&addr->addressLength) == 4
|
|
|
|
&& inet_ntop(AF_INET, addr->address, buf, sizeof(buf)))
|
|
|
|
return buf;
|
|
|
|
break;
|
|
|
|
case TRANS_UDP_IPV6:
|
|
|
|
if (align16(&addr->addressLength) == 16
|
|
|
|
&& inet_ntop(AF_INET6, addr->address, buf, sizeof(buf)))
|
|
|
|
return buf;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bin2str_impl(addr->address, align16(&addr->addressLength), buf, sizeof(buf));
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2012-08-05 20:14:44 +08:00
|
|
|
static void pmc_show(struct ptp_message *msg, FILE *fp)
|
|
|
|
{
|
|
|
|
int action;
|
|
|
|
struct TLV *tlv;
|
2012-08-22 21:49:04 +08:00
|
|
|
struct management_tlv *mgt;
|
2013-03-04 02:41:06 +08:00
|
|
|
struct management_tlv_datum *mtd;
|
2012-12-02 14:49:21 +08:00
|
|
|
struct defaultDS *dds;
|
2012-08-22 21:49:04 +08:00
|
|
|
struct currentDS *cds;
|
2012-12-02 17:09:30 +08:00
|
|
|
struct parentDS *pds;
|
2012-12-03 03:13:06 +08:00
|
|
|
struct timePropertiesDS *tp;
|
2012-09-12 23:44:20 +08:00
|
|
|
struct time_status_np *tsn;
|
2013-07-06 17:21:57 +08:00
|
|
|
struct grandmaster_settings_np *gsn;
|
2013-02-25 07:56:38 +08:00
|
|
|
struct mgmt_clock_description *cd;
|
2018-02-08 02:58:39 +08:00
|
|
|
struct tlv_extra *extra;
|
2012-12-03 04:07:43 +08:00
|
|
|
struct portDS *p;
|
2014-02-04 17:56:06 +08:00
|
|
|
struct port_ds_np *pnp;
|
2018-02-08 02:58:39 +08:00
|
|
|
|
2012-08-05 20:14:44 +08:00
|
|
|
if (msg_type(msg) != MANAGEMENT) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
action = management_action(msg);
|
|
|
|
if (action < GET || action > ACKNOWLEDGE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fprintf(fp, "\t%s seq %hu %s ",
|
|
|
|
pid2str(&msg->header.sourcePortIdentity),
|
|
|
|
msg->header.sequenceId, action_string[action]);
|
|
|
|
if (msg->tlv_count != 1) {
|
|
|
|
goto out;
|
|
|
|
}
|
2018-02-08 02:58:39 +08:00
|
|
|
extra = TAILQ_FIRST(&msg->tlv_list);
|
2012-08-05 20:14:44 +08:00
|
|
|
tlv = (struct TLV *) msg->management.suffix;
|
|
|
|
if (tlv->type == TLV_MANAGEMENT) {
|
2015-06-08 15:34:41 +08:00
|
|
|
fprintf(fp, "MANAGEMENT ");
|
2012-08-05 20:14:44 +08:00
|
|
|
} else if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS) {
|
2015-06-08 15:34:41 +08:00
|
|
|
fprintf(fp, "MANAGEMENT_ERROR_STATUS ");
|
2012-08-22 21:49:04 +08:00
|
|
|
goto out;
|
2012-08-05 20:14:44 +08:00
|
|
|
} else {
|
|
|
|
fprintf(fp, "unknown-tlv ");
|
2017-05-23 14:49:55 +08:00
|
|
|
goto out;
|
2012-08-05 20:14:44 +08:00
|
|
|
}
|
2012-08-22 21:49:04 +08:00
|
|
|
mgt = (struct management_tlv *) msg->management.suffix;
|
2014-06-25 18:45:23 +08:00
|
|
|
if (mgt->length == 2 && mgt->id != TLV_NULL_MANAGEMENT) {
|
2013-03-12 05:29:18 +08:00
|
|
|
fprintf(fp, "empty-tlv ");
|
|
|
|
goto out;
|
|
|
|
}
|
2012-08-22 21:49:04 +08:00
|
|
|
switch (mgt->id) {
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_CLOCK_DESCRIPTION:
|
2018-02-08 02:58:39 +08:00
|
|
|
cd = &extra->cd;
|
2013-02-25 07:56:38 +08:00
|
|
|
fprintf(fp, "CLOCK_DESCRIPTION "
|
|
|
|
IFMT "clockType 0x%hx"
|
|
|
|
IFMT "physicalLayerProtocol %s"
|
|
|
|
IFMT "physicalAddress %s"
|
|
|
|
IFMT "protocolAddress %hu %s",
|
|
|
|
align16(cd->clockType),
|
2017-11-26 03:07:22 +08:00
|
|
|
text2str(cd->physicalLayerProtocol),
|
2013-02-25 07:56:38 +08:00
|
|
|
bin2str(cd->physicalAddress->address,
|
2017-11-26 03:07:22 +08:00
|
|
|
align16(&cd->physicalAddress->length)),
|
2013-02-25 07:56:38 +08:00
|
|
|
align16(&cd->protocolAddress->networkProtocol),
|
|
|
|
portaddr2str(cd->protocolAddress));
|
|
|
|
fprintf(fp, IFMT "manufacturerId %s"
|
2017-11-26 03:07:22 +08:00
|
|
|
IFMT "productDescription %s",
|
2013-02-25 07:56:38 +08:00
|
|
|
bin2str(cd->manufacturerIdentity, OUI_LEN),
|
|
|
|
text2str(cd->productDescription));
|
|
|
|
fprintf(fp, IFMT "revisionData %s",
|
2017-11-26 03:07:22 +08:00
|
|
|
text2str(cd->revisionData));
|
2013-02-25 07:56:38 +08:00
|
|
|
fprintf(fp, IFMT "userDescription %s"
|
2017-11-26 03:07:22 +08:00
|
|
|
IFMT "profileId %s",
|
2013-02-25 07:56:38 +08:00
|
|
|
text2str(cd->userDescription),
|
|
|
|
bin2str(cd->profileIdentity, PROFILE_ID_LEN));
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_USER_DESCRIPTION:
|
2013-02-25 07:56:38 +08:00
|
|
|
fprintf(fp, "USER_DESCRIPTION "
|
|
|
|
IFMT "userDescription %s",
|
2018-02-08 02:58:39 +08:00
|
|
|
text2str(extra->cd.userDescription));
|
2013-02-25 07:56:38 +08:00
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_DEFAULT_DATA_SET:
|
2012-12-02 14:49:21 +08:00
|
|
|
dds = (struct defaultDS *) mgt->data;
|
|
|
|
fprintf(fp, "DEFAULT_DATA_SET "
|
2012-12-04 23:03:33 +08:00
|
|
|
IFMT "twoStepFlag %d"
|
|
|
|
IFMT "slaveOnly %d"
|
2012-12-02 17:13:15 +08:00
|
|
|
IFMT "numberPorts %hu"
|
|
|
|
IFMT "priority1 %hhu"
|
2012-12-04 20:21:53 +08:00
|
|
|
IFMT "clockClass %hhu"
|
|
|
|
IFMT "clockAccuracy 0x%02hhx"
|
2012-12-02 17:13:15 +08:00
|
|
|
IFMT "offsetScaledLogVariance 0x%04hx"
|
|
|
|
IFMT "priority2 %hhu"
|
|
|
|
IFMT "clockIdentity %s"
|
|
|
|
IFMT "domainNumber %hhu",
|
2012-12-04 23:03:33 +08:00
|
|
|
dds->flags & DDS_TWO_STEP_FLAG ? 1 : 0,
|
|
|
|
dds->flags & DDS_SLAVE_ONLY ? 1 : 0,
|
2012-12-02 14:49:21 +08:00
|
|
|
dds->numberPorts,
|
|
|
|
dds->priority1,
|
|
|
|
dds->clockQuality.clockClass,
|
|
|
|
dds->clockQuality.clockAccuracy,
|
|
|
|
dds->clockQuality.offsetScaledLogVariance,
|
|
|
|
dds->priority2,
|
|
|
|
cid2str(&dds->clockIdentity),
|
|
|
|
dds->domainNumber);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_CURRENT_DATA_SET:
|
2012-08-22 21:49:04 +08:00
|
|
|
cds = (struct currentDS *) mgt->data;
|
|
|
|
fprintf(fp, "CURRENT_DATA_SET "
|
2012-12-02 17:13:15 +08:00
|
|
|
IFMT "stepsRemoved %hd"
|
|
|
|
IFMT "offsetFromMaster %.1f"
|
|
|
|
IFMT "meanPathDelay %.1f",
|
2012-08-22 21:49:04 +08:00
|
|
|
cds->stepsRemoved, cds->offsetFromMaster / 65536.0,
|
|
|
|
cds->meanPathDelay / 65536.0);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_PARENT_DATA_SET:
|
2012-12-02 17:09:30 +08:00
|
|
|
pds = (struct parentDS *) mgt->data;
|
|
|
|
fprintf(fp, "PARENT_DATA_SET "
|
|
|
|
IFMT "parentPortIdentity %s"
|
|
|
|
IFMT "parentStats %hhu"
|
|
|
|
IFMT "observedParentOffsetScaledLogVariance 0x%04hx"
|
2012-12-04 20:21:53 +08:00
|
|
|
IFMT "observedParentClockPhaseChangeRate 0x%08x"
|
2012-12-02 17:09:30 +08:00
|
|
|
IFMT "grandmasterPriority1 %hhu"
|
2012-12-04 20:21:53 +08:00
|
|
|
IFMT "gm.ClockClass %hhu"
|
|
|
|
IFMT "gm.ClockAccuracy 0x%02hhx"
|
2012-12-02 17:09:30 +08:00
|
|
|
IFMT "gm.OffsetScaledLogVariance 0x%04hx"
|
|
|
|
IFMT "grandmasterPriority2 %hhu"
|
|
|
|
IFMT "grandmasterIdentity %s",
|
|
|
|
pid2str(&pds->parentPortIdentity),
|
|
|
|
pds->parentStats,
|
|
|
|
pds->observedParentOffsetScaledLogVariance,
|
|
|
|
pds->observedParentClockPhaseChangeRate,
|
|
|
|
pds->grandmasterPriority1,
|
|
|
|
pds->grandmasterClockQuality.clockClass,
|
|
|
|
pds->grandmasterClockQuality.clockAccuracy,
|
|
|
|
pds->grandmasterClockQuality.offsetScaledLogVariance,
|
|
|
|
pds->grandmasterPriority2,
|
|
|
|
cid2str(&pds->grandmasterIdentity));
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_TIME_PROPERTIES_DATA_SET:
|
2012-12-03 03:13:06 +08:00
|
|
|
tp = (struct timePropertiesDS *) mgt->data;
|
|
|
|
fprintf(fp, "TIME_PROPERTIES_DATA_SET "
|
|
|
|
IFMT "currentUtcOffset %hd"
|
|
|
|
IFMT "leap61 %d"
|
|
|
|
IFMT "leap59 %d"
|
|
|
|
IFMT "currentUtcOffsetValid %d"
|
|
|
|
IFMT "ptpTimescale %d"
|
|
|
|
IFMT "timeTraceable %d"
|
|
|
|
IFMT "frequencyTraceable %d"
|
2012-12-04 20:21:53 +08:00
|
|
|
IFMT "timeSource 0x%02hhx",
|
2012-12-03 03:13:06 +08:00
|
|
|
tp->currentUtcOffset,
|
|
|
|
tp->flags & LEAP_61 ? 1 : 0,
|
|
|
|
tp->flags & LEAP_59 ? 1 : 0,
|
|
|
|
tp->flags & UTC_OFF_VALID ? 1 : 0,
|
|
|
|
tp->flags & PTP_TIMESCALE ? 1 : 0,
|
|
|
|
tp->flags & TIME_TRACEABLE ? 1 : 0,
|
|
|
|
tp->flags & FREQ_TRACEABLE ? 1 : 0,
|
|
|
|
tp->timeSource);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_PRIORITY1:
|
2013-03-04 02:41:06 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "PRIORITY1 "
|
|
|
|
IFMT "priority1 %hhu", mtd->val);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_PRIORITY2:
|
2013-03-04 02:48:43 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "PRIORITY2 "
|
|
|
|
IFMT "priority2 %hhu", mtd->val);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_DOMAIN:
|
2013-03-04 02:54:17 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "DOMAIN "
|
|
|
|
IFMT "domainNumber %hhu", mtd->val);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_SLAVE_ONLY:
|
2013-03-04 03:06:17 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "SLAVE_ONLY "
|
|
|
|
IFMT "slaveOnly %d", mtd->val & DDS_SLAVE_ONLY ? 1 : 0);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_CLOCK_ACCURACY:
|
2013-03-04 03:10:46 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "CLOCK_ACCURACY "
|
|
|
|
IFMT "clockAccuracy 0x%02hhx", mtd->val);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_TRACEABILITY_PROPERTIES:
|
2013-03-04 03:20:12 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "TRACEABILITY_PROPERTIES "
|
|
|
|
IFMT "timeTraceable %d"
|
|
|
|
IFMT "frequencyTraceable %d",
|
|
|
|
mtd->val & TIME_TRACEABLE ? 1 : 0,
|
|
|
|
mtd->val & FREQ_TRACEABLE ? 1 : 0);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_TIMESCALE_PROPERTIES:
|
2013-03-04 03:26:00 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "TIMESCALE_PROPERTIES "
|
|
|
|
IFMT "ptpTimescale %d", mtd->val & PTP_TIMESCALE ? 1 : 0);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_TIME_STATUS_NP:
|
2012-09-12 23:44:20 +08:00
|
|
|
tsn = (struct time_status_np *) mgt->data;
|
|
|
|
fprintf(fp, "TIME_STATUS_NP "
|
2012-12-18 21:00:49 +08:00
|
|
|
IFMT "master_offset %" PRId64
|
|
|
|
IFMT "ingress_time %" PRId64
|
2012-12-02 17:13:15 +08:00
|
|
|
IFMT "cumulativeScaledRateOffset %+.9f"
|
|
|
|
IFMT "scaledLastGmPhaseChange %d"
|
|
|
|
IFMT "gmTimeBaseIndicator %hu"
|
2012-12-18 21:00:49 +08:00
|
|
|
IFMT "lastGmPhaseChange 0x%04hx'%016" PRIx64 ".%04hx"
|
2012-12-02 17:13:15 +08:00
|
|
|
IFMT "gmPresent %s"
|
|
|
|
IFMT "gmIdentity %s",
|
2012-09-12 23:44:20 +08:00
|
|
|
tsn->master_offset,
|
|
|
|
tsn->ingress_time,
|
2014-02-21 18:08:35 +08:00
|
|
|
(tsn->cumulativeScaledRateOffset + 0.0) / P41,
|
2012-09-12 23:44:20 +08:00
|
|
|
tsn->scaledLastGmPhaseChange,
|
|
|
|
tsn->gmTimeBaseIndicator,
|
|
|
|
tsn->lastGmPhaseChange.nanoseconds_msb,
|
|
|
|
tsn->lastGmPhaseChange.nanoseconds_lsb,
|
|
|
|
tsn->lastGmPhaseChange.fractional_nanoseconds,
|
|
|
|
tsn->gmPresent ? "true" : "false",
|
|
|
|
cid2str(&tsn->gmIdentity));
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_GRANDMASTER_SETTINGS_NP:
|
2013-07-06 17:21:57 +08:00
|
|
|
gsn = (struct grandmaster_settings_np *) mgt->data;
|
|
|
|
fprintf(fp, "GRANDMASTER_SETTINGS_NP "
|
|
|
|
IFMT "clockClass %hhu"
|
|
|
|
IFMT "clockAccuracy 0x%02hhx"
|
|
|
|
IFMT "offsetScaledLogVariance 0x%04hx"
|
|
|
|
IFMT "currentUtcOffset %hd"
|
|
|
|
IFMT "leap61 %d"
|
|
|
|
IFMT "leap59 %d"
|
|
|
|
IFMT "currentUtcOffsetValid %d"
|
|
|
|
IFMT "ptpTimescale %d"
|
|
|
|
IFMT "timeTraceable %d"
|
|
|
|
IFMT "frequencyTraceable %d"
|
|
|
|
IFMT "timeSource 0x%02hhx",
|
|
|
|
gsn->clockQuality.clockClass,
|
|
|
|
gsn->clockQuality.clockAccuracy,
|
|
|
|
gsn->clockQuality.offsetScaledLogVariance,
|
|
|
|
gsn->utc_offset,
|
|
|
|
gsn->time_flags & LEAP_61 ? 1 : 0,
|
|
|
|
gsn->time_flags & LEAP_59 ? 1 : 0,
|
|
|
|
gsn->time_flags & UTC_OFF_VALID ? 1 : 0,
|
|
|
|
gsn->time_flags & PTP_TIMESCALE ? 1 : 0,
|
|
|
|
gsn->time_flags & TIME_TRACEABLE ? 1 : 0,
|
|
|
|
gsn->time_flags & FREQ_TRACEABLE ? 1 : 0,
|
|
|
|
gsn->time_source);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_PORT_DATA_SET:
|
2012-12-03 04:07:43 +08:00
|
|
|
p = (struct portDS *) mgt->data;
|
2012-12-04 21:26:50 +08:00
|
|
|
if (p->portState > PS_SLAVE) {
|
|
|
|
p->portState = 0;
|
|
|
|
}
|
2012-12-03 04:07:43 +08:00
|
|
|
fprintf(fp, "PORT_DATA_SET "
|
|
|
|
IFMT "portIdentity %s"
|
2012-12-04 21:26:50 +08:00
|
|
|
IFMT "portState %s"
|
2012-12-03 04:07:43 +08:00
|
|
|
IFMT "logMinDelayReqInterval %hhd"
|
2012-12-18 21:00:49 +08:00
|
|
|
IFMT "peerMeanPathDelay %" PRId64
|
2012-12-03 04:07:43 +08:00
|
|
|
IFMT "logAnnounceInterval %hhd"
|
|
|
|
IFMT "announceReceiptTimeout %hhu"
|
|
|
|
IFMT "logSyncInterval %hhd"
|
|
|
|
IFMT "delayMechanism %hhu"
|
|
|
|
IFMT "logMinPdelayReqInterval %hhd"
|
|
|
|
IFMT "versionNumber %hhu",
|
2012-12-04 21:26:50 +08:00
|
|
|
pid2str(&p->portIdentity), ps_str[p->portState],
|
2012-12-03 04:07:43 +08:00
|
|
|
p->logMinDelayReqInterval, p->peerMeanPathDelay >> 16,
|
|
|
|
p->logAnnounceInterval, p->announceReceiptTimeout,
|
|
|
|
p->logSyncInterval, p->delayMechanism,
|
|
|
|
p->logMinPdelayReqInterval, p->versionNumber);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_PORT_DATA_SET_NP:
|
2014-02-04 17:56:06 +08:00
|
|
|
pnp = (struct port_ds_np *) mgt->data;
|
|
|
|
fprintf(fp, "PORT_DATA_SET_NP "
|
|
|
|
IFMT "neighborPropDelayThresh %u"
|
|
|
|
IFMT "asCapable %d",
|
|
|
|
pnp->neighborPropDelayThresh,
|
|
|
|
pnp->asCapable ? 1 : 0);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_LOG_ANNOUNCE_INTERVAL:
|
2013-03-05 03:06:36 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "LOG_ANNOUNCE_INTERVAL "
|
|
|
|
IFMT "logAnnounceInterval %hhd", mtd->val);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_ANNOUNCE_RECEIPT_TIMEOUT:
|
2013-03-05 03:10:51 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "ANNOUNCE_RECEIPT_TIMEOUT "
|
|
|
|
IFMT "announceReceiptTimeout %hhu", mtd->val);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_LOG_SYNC_INTERVAL:
|
2013-03-05 03:14:05 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "ANNOUNCE_RECEIPT_TIMEOUT "
|
|
|
|
IFMT "logSyncInterval %hhd", mtd->val);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_VERSION_NUMBER:
|
2013-03-05 03:18:19 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "VERSION_NUMBER "
|
|
|
|
IFMT "versionNumber %hhu", mtd->val);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_DELAY_MECHANISM:
|
2013-03-05 03:23:32 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "DELAY_MECHANISM "
|
|
|
|
IFMT "delayMechanism %hhu", mtd->val);
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_LOG_MIN_PDELAY_REQ_INTERVAL:
|
2013-03-05 03:27:12 +08:00
|
|
|
mtd = (struct management_tlv_datum *) mgt->data;
|
|
|
|
fprintf(fp, "LOG_MIN_PDELAY_REQ_INTERVAL "
|
|
|
|
IFMT "logMinPdelayReqInterval %hhd", mtd->val);
|
|
|
|
break;
|
2012-08-22 21:49:04 +08:00
|
|
|
}
|
2012-08-05 20:14:44 +08:00
|
|
|
out:
|
|
|
|
fprintf(fp, "\n");
|
|
|
|
fflush(fp);
|
|
|
|
}
|
|
|
|
|
2013-07-06 20:00:43 +08:00
|
|
|
static void do_get_action(int action, int index, char *str)
|
2012-08-22 13:18:59 +08:00
|
|
|
{
|
|
|
|
if (action == GET)
|
2013-01-31 01:31:50 +08:00
|
|
|
pmc_send_get_action(pmc, idtab[index].code);
|
2012-08-22 13:18:59 +08:00
|
|
|
else
|
|
|
|
fprintf(stderr, "%s only allows GET\n", idtab[index].name);
|
|
|
|
}
|
|
|
|
|
2013-07-06 20:00:43 +08:00
|
|
|
static void do_set_action(int action, int index, char *str)
|
|
|
|
{
|
|
|
|
struct grandmaster_settings_np gsn;
|
2015-03-18 03:10:33 +08:00
|
|
|
struct management_tlv_datum mtd;
|
2014-02-04 17:56:06 +08:00
|
|
|
struct port_ds_np pnp;
|
2013-07-06 20:00:43 +08:00
|
|
|
int cnt, code = idtab[index].code;
|
|
|
|
int leap_61, leap_59, utc_off_valid;
|
|
|
|
int ptp_timescale, time_traceable, freq_traceable;
|
|
|
|
|
|
|
|
switch (action) {
|
|
|
|
case GET:
|
|
|
|
pmc_send_get_action(pmc, code);
|
|
|
|
return;
|
|
|
|
case SET:
|
|
|
|
break;
|
|
|
|
case RESPONSE:
|
|
|
|
case COMMAND:
|
|
|
|
case ACKNOWLEDGE:
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "%s only allows GET or SET\n",
|
|
|
|
idtab[index].name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (code) {
|
2015-03-18 03:10:33 +08:00
|
|
|
case TLV_PRIORITY1:
|
|
|
|
case TLV_PRIORITY2:
|
|
|
|
cnt = sscanf(str, " %*s %*s %hhu", &mtd.val);
|
|
|
|
if (cnt != 1) {
|
|
|
|
fprintf(stderr, "%s SET needs 1 value\n",
|
|
|
|
idtab[index].name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pmc_send_set_action(pmc, code, &mtd, sizeof(mtd));
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_GRANDMASTER_SETTINGS_NP:
|
2013-07-06 20:00:43 +08:00
|
|
|
cnt = sscanf(str, " %*s %*s "
|
|
|
|
"clockClass %hhu "
|
|
|
|
"clockAccuracy %hhx "
|
|
|
|
"offsetScaledLogVariance %hx "
|
|
|
|
"currentUtcOffset %hd "
|
|
|
|
"leap61 %d "
|
|
|
|
"leap59 %d "
|
|
|
|
"currentUtcOffsetValid %d "
|
|
|
|
"ptpTimescale %d "
|
|
|
|
"timeTraceable %d "
|
|
|
|
"frequencyTraceable %d "
|
|
|
|
"timeSource %hhx ",
|
|
|
|
&gsn.clockQuality.clockClass,
|
|
|
|
&gsn.clockQuality.clockAccuracy,
|
|
|
|
&gsn.clockQuality.offsetScaledLogVariance,
|
|
|
|
&gsn.utc_offset,
|
|
|
|
&leap_61,
|
|
|
|
&leap_59,
|
|
|
|
&utc_off_valid,
|
|
|
|
&ptp_timescale,
|
|
|
|
&time_traceable,
|
|
|
|
&freq_traceable,
|
|
|
|
&gsn.time_source);
|
|
|
|
if (cnt != 11) {
|
|
|
|
fprintf(stderr, "%s SET needs 11 values\n",
|
|
|
|
idtab[index].name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
gsn.time_flags = 0;
|
|
|
|
if (leap_61)
|
|
|
|
gsn.time_flags |= LEAP_61;
|
|
|
|
if (leap_59)
|
|
|
|
gsn.time_flags |= LEAP_59;
|
|
|
|
if (utc_off_valid)
|
|
|
|
gsn.time_flags |= UTC_OFF_VALID;
|
|
|
|
if (ptp_timescale)
|
|
|
|
gsn.time_flags |= PTP_TIMESCALE;
|
|
|
|
if (time_traceable)
|
|
|
|
gsn.time_flags |= TIME_TRACEABLE;
|
|
|
|
if (freq_traceable)
|
|
|
|
gsn.time_flags |= FREQ_TRACEABLE;
|
|
|
|
pmc_send_set_action(pmc, code, &gsn, sizeof(gsn));
|
|
|
|
break;
|
2014-06-25 18:45:23 +08:00
|
|
|
case TLV_PORT_DATA_SET_NP:
|
2014-02-04 17:56:06 +08:00
|
|
|
cnt = sscanf(str, " %*s %*s "
|
|
|
|
"neighborPropDelayThresh %u "
|
|
|
|
"asCapable %d ",
|
|
|
|
&pnp.neighborPropDelayThresh,
|
|
|
|
&pnp.asCapable);
|
|
|
|
if (cnt != 2) {
|
|
|
|
fprintf(stderr, "%s SET needs 2 values\n",
|
|
|
|
idtab[index].name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pmc_send_set_action(pmc, code, &pnp, sizeof(pnp));
|
|
|
|
break;
|
2013-07-06 20:00:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void not_supported(int action, int index, char *str)
|
2012-08-05 20:14:44 +08:00
|
|
|
{
|
|
|
|
fprintf(stdout, "sorry, %s not supported yet\n", idtab[index].name);
|
|
|
|
}
|
|
|
|
|
2013-07-06 20:00:43 +08:00
|
|
|
static void null_management(int action, int index, char *str)
|
2012-08-05 20:14:44 +08:00
|
|
|
{
|
|
|
|
if (action == GET)
|
2013-01-31 01:31:50 +08:00
|
|
|
pmc_send_get_action(pmc, idtab[index].code);
|
2012-08-22 13:17:04 +08:00
|
|
|
else
|
|
|
|
puts("non-get actions still todo");
|
2012-08-05 20:14:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_action(char *s)
|
|
|
|
{
|
|
|
|
int len = strlen(s);
|
|
|
|
if (0 == strncasecmp(s, "GET", len))
|
|
|
|
return GET;
|
|
|
|
else if (0 == strncasecmp(s, "SET", len))
|
|
|
|
return SET;
|
|
|
|
else if (0 == strncasecmp(s, "CMD", len))
|
|
|
|
return COMMAND;
|
|
|
|
else if (0 == strncasecmp(s, "COMMAND", len))
|
|
|
|
return COMMAND;
|
|
|
|
return BAD_ACTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_id(char *s)
|
|
|
|
{
|
|
|
|
int i, index = BAD_ID, len = strlen(s);
|
2012-12-29 05:51:14 +08:00
|
|
|
/* check for exact match */
|
|
|
|
for (i = 0; i < ARRAY_SIZE(idtab); i++) {
|
|
|
|
if (strcasecmp(s, idtab[i].name) == 0) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* look for a unique prefix match */
|
2012-08-05 20:14:44 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(idtab); i++) {
|
|
|
|
if (0 == strncasecmp(s, idtab[i].name, len)) {
|
|
|
|
if (index == BAD_ID)
|
|
|
|
index = i;
|
|
|
|
else
|
|
|
|
return AMBIGUOUS_ID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
2013-07-22 13:37:22 +08:00
|
|
|
static int parse_target(const char *str)
|
|
|
|
{
|
|
|
|
struct PortIdentity pid;
|
|
|
|
|
|
|
|
if (str[0] == '*') {
|
|
|
|
memset(&pid, 0xff, sizeof(pid));
|
|
|
|
} else if (str2pid(str, &pid)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pmc_target(pmc, &pid);
|
|
|
|
}
|
|
|
|
|
2012-08-29 01:16:08 +08:00
|
|
|
static void print_help(FILE *fp)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
fprintf(fp, "\n");
|
|
|
|
for (i = 0; i < ARRAY_SIZE(idtab); i++) {
|
|
|
|
if (idtab[i].func != not_supported)
|
|
|
|
fprintf(fp, "\t[action] %s\n", idtab[i].name);
|
|
|
|
}
|
|
|
|
fprintf(fp, "\n");
|
|
|
|
fprintf(fp, "\tThe [action] can be GET, SET, CMD, or COMMAND\n");
|
|
|
|
fprintf(fp, "\tCommands are case insensitive and may be abbreviated.\n");
|
|
|
|
fprintf(fp, "\n");
|
2013-07-22 13:37:22 +08:00
|
|
|
fprintf(fp, "\tTARGET [portIdentity]\n");
|
|
|
|
fprintf(fp, "\tTARGET *\n");
|
|
|
|
fprintf(fp, "\n");
|
2012-08-29 01:16:08 +08:00
|
|
|
}
|
|
|
|
|
2012-08-05 20:14:44 +08:00
|
|
|
static int do_command(char *str)
|
|
|
|
{
|
|
|
|
int action, id;
|
|
|
|
char action_str[10+1] = {0}, id_str[64+1] = {0};
|
|
|
|
|
2012-08-29 01:16:08 +08:00
|
|
|
if (0 == strncasecmp(str, "HELP", strlen(str))) {
|
|
|
|
print_help(stdout);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-05 20:14:44 +08:00
|
|
|
if (2 != sscanf(str, " %10s %64s", action_str, id_str))
|
|
|
|
return -1;
|
|
|
|
|
2013-07-22 13:37:22 +08:00
|
|
|
if (0 == strncasecmp(action_str, "TARGET", strlen(action_str)))
|
|
|
|
return parse_target(id_str);
|
|
|
|
|
2012-08-05 20:14:44 +08:00
|
|
|
action = parse_action(action_str);
|
|
|
|
id = parse_id(id_str);
|
|
|
|
|
|
|
|
if (action == BAD_ACTION || id == BAD_ID)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (id == AMBIGUOUS_ID) {
|
|
|
|
fprintf(stdout, "id %s is too ambiguous\n", id_str);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-22 13:17:04 +08:00
|
|
|
fprintf(stdout, "sending: %s %s\n",
|
|
|
|
action_string[action], idtab[id].name);
|
|
|
|
|
2013-07-06 20:00:43 +08:00
|
|
|
idtab[id].func(action, id, str);
|
2012-08-05 20:14:44 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void usage(char *progname)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
2013-02-06 00:36:06 +08:00
|
|
|
"\nusage: %s [options] [commands]\n\n"
|
2012-08-05 20:14:44 +08:00
|
|
|
" Network Transport\n\n"
|
|
|
|
" -2 IEEE 802.3\n"
|
|
|
|
" -4 UDP IPV4 (default)\n"
|
2012-08-24 23:50:39 +08:00
|
|
|
" -6 UDP IPV6\n"
|
|
|
|
" -u UDS local\n\n"
|
2012-08-05 20:14:44 +08:00
|
|
|
" Other Options\n\n"
|
2012-08-25 15:46:34 +08:00
|
|
|
" -b [num] boundary hops, default 1\n"
|
|
|
|
" -d [num] domain number, default 0\n"
|
2012-08-05 20:14:44 +08:00
|
|
|
" -h prints this message and exits\n"
|
|
|
|
" -i [dev] interface device to use, default 'eth0'\n"
|
2014-07-08 22:14:22 +08:00
|
|
|
" for network and '/var/run/pmc.$pid' for UDS.\n"
|
2013-09-30 02:58:17 +08:00
|
|
|
" -s [path] server address for UDS, default '/var/run/ptp4l'.\n"
|
2012-08-25 15:46:34 +08:00
|
|
|
" -t [hex] transport specific field, default 0x0\n"
|
2012-12-10 17:28:28 +08:00
|
|
|
" -v prints the software version and exits\n"
|
2013-07-22 02:48:20 +08:00
|
|
|
" -z send zero length TLV values with the GET actions\n"
|
2012-08-05 20:14:44 +08:00
|
|
|
"\n",
|
|
|
|
progname);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2014-02-08 00:52:03 +08:00
|
|
|
const char *iface_name = NULL;
|
|
|
|
char *progname;
|
2013-07-22 02:48:20 +08:00
|
|
|
int c, cnt, length, tmo = -1, batch_mode = 0, zero_datalen = 0;
|
2014-07-08 22:14:21 +08:00
|
|
|
int ret = 0;
|
2014-07-08 22:14:22 +08:00
|
|
|
char line[1024], *command = NULL, uds_local[MAX_IFNAME_SIZE + 1];
|
2012-08-05 20:14:44 +08:00
|
|
|
enum transport_type transport_type = TRANS_UDP_IPV4;
|
2013-01-31 01:31:50 +08:00
|
|
|
UInteger8 boundary_hops = 1, domain_number = 0, transport_specific = 0;
|
2012-08-05 20:14:44 +08:00
|
|
|
struct ptp_message *msg;
|
2015-08-23 19:59:38 +08:00
|
|
|
struct config *cfg;
|
2012-08-05 20:14:44 +08:00
|
|
|
#define N_FD 2
|
|
|
|
struct pollfd pollfd[N_FD];
|
|
|
|
|
2014-07-08 22:14:21 +08:00
|
|
|
handle_term_signals();
|
|
|
|
|
2015-08-23 19:59:38 +08:00
|
|
|
cfg = config_create();
|
|
|
|
if (!cfg) {
|
2015-08-13 00:34:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-05 20:14:44 +08:00
|
|
|
/* Process the command line arguments. */
|
|
|
|
progname = strrchr(argv[0], '/');
|
|
|
|
progname = progname ? 1+progname : argv[0];
|
2013-09-30 02:58:17 +08:00
|
|
|
while (EOF != (c = getopt(argc, argv, "246u""b:d:hi:s:t:vz"))) {
|
2012-08-05 20:14:44 +08:00
|
|
|
switch (c) {
|
|
|
|
case '2':
|
|
|
|
transport_type = TRANS_IEEE_802_3;
|
|
|
|
break;
|
|
|
|
case '4':
|
|
|
|
transport_type = TRANS_UDP_IPV4;
|
|
|
|
break;
|
|
|
|
case '6':
|
|
|
|
transport_type = TRANS_UDP_IPV6;
|
|
|
|
break;
|
2012-08-24 23:50:39 +08:00
|
|
|
case 'u':
|
|
|
|
transport_type = TRANS_UDS;
|
|
|
|
break;
|
2012-08-25 15:46:34 +08:00
|
|
|
case 'b':
|
|
|
|
boundary_hops = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
domain_number = atoi(optarg);
|
|
|
|
break;
|
2012-08-05 20:14:44 +08:00
|
|
|
case 'i':
|
|
|
|
iface_name = optarg;
|
|
|
|
break;
|
2013-09-30 02:58:17 +08:00
|
|
|
case 's':
|
|
|
|
if (strlen(optarg) > MAX_IFNAME_SIZE) {
|
|
|
|
fprintf(stderr, "path %s too long, max is %d\n",
|
|
|
|
optarg, MAX_IFNAME_SIZE);
|
2015-08-13 00:34:04 +08:00
|
|
|
config_destroy(cfg);
|
2013-09-30 02:58:17 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2015-08-23 19:59:38 +08:00
|
|
|
if (config_set_string(cfg, "uds_address", optarg)) {
|
2015-08-22 05:25:15 +08:00
|
|
|
config_destroy(cfg);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-09-30 02:58:17 +08:00
|
|
|
break;
|
2012-08-25 15:46:34 +08:00
|
|
|
case 't':
|
|
|
|
if (1 == sscanf(optarg, "%x", &c))
|
|
|
|
transport_specific = c << 4;
|
|
|
|
break;
|
2012-12-10 17:28:28 +08:00
|
|
|
case 'v':
|
|
|
|
version_show(stdout);
|
2015-08-13 00:34:04 +08:00
|
|
|
config_destroy(cfg);
|
2012-12-10 17:28:28 +08:00
|
|
|
return 0;
|
2013-07-22 02:48:20 +08:00
|
|
|
case 'z':
|
|
|
|
zero_datalen = 1;
|
|
|
|
break;
|
2012-08-05 20:14:44 +08:00
|
|
|
case 'h':
|
|
|
|
usage(progname);
|
2015-08-13 00:34:04 +08:00
|
|
|
config_destroy(cfg);
|
2012-08-05 20:14:44 +08:00
|
|
|
return 0;
|
|
|
|
case '?':
|
|
|
|
default:
|
|
|
|
usage(progname);
|
2015-08-13 00:34:04 +08:00
|
|
|
config_destroy(cfg);
|
2012-08-05 20:14:44 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-25 15:30:44 +08:00
|
|
|
if (!iface_name) {
|
2014-07-08 22:14:22 +08:00
|
|
|
if (transport_type == TRANS_UDS) {
|
|
|
|
snprintf(uds_local, sizeof(uds_local),
|
|
|
|
"/var/run/pmc.%d", getpid());
|
|
|
|
iface_name = uds_local;
|
|
|
|
} else {
|
|
|
|
iface_name = "eth0";
|
|
|
|
}
|
2012-08-25 15:30:44 +08:00
|
|
|
}
|
2013-02-06 00:36:06 +08:00
|
|
|
if (optind < argc) {
|
|
|
|
batch_mode = 1;
|
|
|
|
}
|
2013-01-31 01:31:50 +08:00
|
|
|
|
|
|
|
print_set_progname(progname);
|
|
|
|
print_set_syslog(1);
|
|
|
|
print_set_verbose(1);
|
|
|
|
|
2015-08-23 19:59:38 +08:00
|
|
|
pmc = pmc_create(cfg, transport_type, iface_name, boundary_hops,
|
2013-07-22 02:48:20 +08:00
|
|
|
domain_number, transport_specific, zero_datalen);
|
2013-01-31 01:31:50 +08:00
|
|
|
if (!pmc) {
|
|
|
|
fprintf(stderr, "failed to create pmc\n");
|
2015-08-13 00:34:04 +08:00
|
|
|
config_destroy(cfg);
|
2012-08-05 20:14:44 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-02-06 00:36:06 +08:00
|
|
|
pollfd[0].fd = batch_mode ? -1 : STDIN_FILENO;
|
2013-01-31 01:31:50 +08:00
|
|
|
pollfd[1].fd = pmc_get_transport_fd(pmc);
|
2012-08-05 20:14:44 +08:00
|
|
|
|
2014-07-08 22:14:21 +08:00
|
|
|
while (is_running()) {
|
2013-02-06 00:36:06 +08:00
|
|
|
if (batch_mode && !command) {
|
|
|
|
if (optind < argc) {
|
|
|
|
command = argv[optind++];
|
|
|
|
} else {
|
|
|
|
/* No more commands, wait a bit for
|
|
|
|
any outstanding replies and exit. */
|
|
|
|
tmo = 100;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pollfd[0].events = 0;
|
|
|
|
pollfd[1].events = POLLIN | POLLPRI;
|
|
|
|
|
|
|
|
if (!batch_mode && !command)
|
|
|
|
pollfd[0].events |= POLLIN | POLLPRI;
|
|
|
|
if (command)
|
|
|
|
pollfd[1].events |= POLLOUT;
|
|
|
|
|
2012-08-25 21:45:54 +08:00
|
|
|
cnt = poll(pollfd, N_FD, tmo);
|
2012-08-05 20:14:44 +08:00
|
|
|
if (cnt < 0) {
|
|
|
|
if (EINTR == errno) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
pr_emerg("poll failed");
|
2014-07-08 22:14:21 +08:00
|
|
|
ret = -1;
|
|
|
|
break;
|
2012-08-05 20:14:44 +08:00
|
|
|
}
|
|
|
|
} else if (!cnt) {
|
2012-08-25 21:45:54 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (pollfd[0].revents & POLLHUP) {
|
|
|
|
if (tmo == -1) {
|
|
|
|
/* Wait a bit longer for outstanding replies. */
|
2012-12-04 21:27:25 +08:00
|
|
|
tmo = 100;
|
2012-08-25 21:45:54 +08:00
|
|
|
pollfd[0].fd = -1;
|
|
|
|
pollfd[0].events = 0;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2012-08-05 20:14:44 +08:00
|
|
|
}
|
|
|
|
if (pollfd[0].revents & (POLLIN|POLLPRI)) {
|
|
|
|
if (!fgets(line, sizeof(line), stdin)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
length = strlen(line);
|
|
|
|
if (length < 2) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
line[length - 1] = 0;
|
2013-02-06 00:36:06 +08:00
|
|
|
command = line;
|
|
|
|
}
|
|
|
|
if (pollfd[1].revents & POLLOUT) {
|
|
|
|
if (do_command(command)) {
|
|
|
|
fprintf(stderr, "bad command: %s\n", command);
|
2012-08-05 20:14:44 +08:00
|
|
|
}
|
2013-02-06 00:36:06 +08:00
|
|
|
command = NULL;
|
2012-08-05 20:14:44 +08:00
|
|
|
}
|
|
|
|
if (pollfd[1].revents & (POLLIN|POLLPRI)) {
|
2013-01-31 01:31:50 +08:00
|
|
|
msg = pmc_recv(pmc);
|
|
|
|
if (msg) {
|
2012-08-05 20:14:44 +08:00
|
|
|
pmc_show(msg, stdout);
|
2013-01-31 01:31:50 +08:00
|
|
|
msg_put(msg);
|
2012-08-05 20:14:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-31 01:31:50 +08:00
|
|
|
pmc_destroy(pmc);
|
2013-07-24 01:56:02 +08:00
|
|
|
msg_cleanup();
|
2015-08-13 00:34:04 +08:00
|
|
|
config_destroy(cfg);
|
2014-07-08 22:14:21 +08:00
|
|
|
return ret;
|
2012-08-05 20:14:44 +08:00
|
|
|
}
|