Blame nsm.c

Packit Service d8d8ac
/**
Packit Service d8d8ac
 * @file nsm.c
Packit Service d8d8ac
 * @brief NSM client program
Packit Service d8d8ac
 * @note Copyright (C) 2018 Richard Cochran <richardcochran@gmail.com>
Packit Service d8d8ac
 *
Packit Service d8d8ac
 * This program is free software; you can redistribute it and/or modify
Packit Service d8d8ac
 * it under the terms of the GNU General Public License as published by
Packit Service d8d8ac
 * the Free Software Foundation; either version 2 of the License, or
Packit Service d8d8ac
 * (at your option) any later version.
Packit Service d8d8ac
 *
Packit Service d8d8ac
 * This program is distributed in the hope that it will be useful,
Packit Service d8d8ac
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service d8d8ac
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service d8d8ac
 * GNU General Public License for more details.
Packit Service d8d8ac
 *
Packit Service d8d8ac
 * You should have received a copy of the GNU General Public License along
Packit Service d8d8ac
 * with this program; if not, write to the Free Software Foundation, Inc.,
Packit Service d8d8ac
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service d8d8ac
 */
Packit Service d8d8ac
#include <errno.h>
Packit Service d8d8ac
#include <poll.h>
Packit Service d8d8ac
#include <stdio.h>
Packit Service d8d8ac
#include <stdlib.h>
Packit Service d8d8ac
#include <string.h>
Packit Service d8d8ac
#include <unistd.h>
Packit Service d8d8ac
#include <inttypes.h>
Packit Service d8d8ac
#include <arpa/inet.h>
Packit Service d8d8ac
Packit Service d8d8ac
#include "config.h"
Packit Service d8d8ac
#include "print.h"
Packit Service d8d8ac
#include "rtnl.h"
Packit Service d8d8ac
#include "util.h"
Packit Service d8d8ac
#include "version.h"
Packit Service d8d8ac
Packit Service d8d8ac
#define IFMT		"\n\t\t"
Packit Service d8d8ac
#define NSM_NFD		3
Packit Service d8d8ac
Packit Service d8d8ac
struct nsm {
Packit Service d8d8ac
	struct config		*cfg;
Packit Service d8d8ac
	struct fdarray		fda;
Packit Service d8d8ac
	struct transport	*trp;
Packit Service d8d8ac
	struct tsproc		*tsproc;
Packit Service d8d8ac
	struct ptp_message	*nsm_delay_req;
Packit Service d8d8ac
	struct ptp_message	*nsm_delay_resp;
Packit Service d8d8ac
	struct ptp_message	*nsm_sync;
Packit Service d8d8ac
	struct ptp_message	*nsm_fup;
Packit Service d8d8ac
	struct PortIdentity	port_identity;
Packit Service d8d8ac
	UInteger16		sequence_id;
Packit Service d8d8ac
	const char		*name;
Packit Service d8d8ac
} the_nsm;
Packit Service d8d8ac
Packit Service d8d8ac
static void nsm_help(FILE *fp);
Packit Service d8d8ac
static int nsm_request(struct nsm *nsm, char *target);
Packit Service d8d8ac
static void nsm_reset(struct nsm *nsm);
Packit Service d8d8ac
Packit Service d8d8ac
static int nsm_command(struct nsm *nsm, const char *cmd)
Packit Service d8d8ac
{
Packit Service d8d8ac
	char action_str[10+1] = {0}, id_str[64+1] = {0};
Packit Service d8d8ac
Packit Service d8d8ac
	if (0 == strncasecmp(cmd, "HELP", strlen(cmd))) {
Packit Service d8d8ac
		nsm_help(stdout);
Packit Service d8d8ac
		return 0;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (2 != sscanf(cmd, " %10s %64s", action_str, id_str)) {
Packit Service d8d8ac
		pr_err("bad command: %s", cmd);
Packit Service d8d8ac
		return -1;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (0 == strncasecmp(action_str, "NSM", strlen(action_str))) {
Packit Service d8d8ac
		return nsm_request(nsm, id_str);
Packit Service d8d8ac
	}
Packit Service d8d8ac
	pr_err("bad command: %s", cmd);
Packit Service d8d8ac
	return -1;
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
static int nsm_complete(struct nsm *nsm)
Packit Service d8d8ac
{
Packit Service d8d8ac
	if (!nsm->nsm_sync) {
Packit Service d8d8ac
		return 0;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (one_step(nsm->nsm_sync)) {
Packit Service d8d8ac
		return nsm->nsm_delay_resp ? 1 : 0;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	return (nsm->nsm_delay_resp && nsm->nsm_fup) ? 1 : 0;
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
static int64_t nsm_compute_offset(struct tsproc *tsp,
Packit Service d8d8ac
				  struct ptp_message *syn,
Packit Service d8d8ac
				  struct ptp_message *fup,
Packit Service d8d8ac
				  struct ptp_message *req,
Packit Service d8d8ac
				  struct ptp_message *resp)
Packit Service d8d8ac
{
Packit Service d8d8ac
	tmv_t c1, c2, c3, t1, t1c, t2, t3, t4, t4c, offset;
Packit Service d8d8ac
Packit Service d8d8ac
	c1 = correction_to_tmv(syn->header.correction);
Packit Service d8d8ac
	c2 = correction_to_tmv(fup->header.correction);
Packit Service d8d8ac
	c3 = correction_to_tmv(resp->header.correction);
Packit Service d8d8ac
Packit Service d8d8ac
	t1 = timestamp_to_tmv(fup->ts.pdu);
Packit Service d8d8ac
	t2 = syn->hwts.ts;
Packit Service d8d8ac
	t3 = req->hwts.ts;
Packit Service d8d8ac
	t4 = timestamp_to_tmv(resp->ts.pdu);
Packit Service d8d8ac
Packit Service d8d8ac
	t1c = tmv_add(t1, tmv_add(c1, c2));
Packit Service d8d8ac
	t4c = tmv_sub(t4, c3);
Packit Service d8d8ac
Packit Service d8d8ac
	tsproc_reset(tsp, 1);
Packit Service d8d8ac
	tsproc_down_ts(tsp, t1c, t2);
Packit Service d8d8ac
	tsproc_up_ts(tsp, t3, t4c);
Packit Service d8d8ac
	tsproc_update_offset(tsp, &offset, NULL);
Packit Service d8d8ac
Packit Service d8d8ac
	return tmv_to_nanoseconds(offset);
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
static void nsm_close(struct nsm *nsm)
Packit Service d8d8ac
{
Packit Service d8d8ac
	nsm_reset(nsm);
Packit Service d8d8ac
	transport_close(nsm->trp, &nsm->fda);
Packit Service d8d8ac
	transport_destroy(nsm->trp);
Packit Service d8d8ac
	tsproc_destroy(nsm->tsproc);
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
static void nsm_handle_msg(struct nsm *nsm, struct ptp_message *msg, FILE *fp)
Packit Service d8d8ac
{
Packit Service d8d8ac
	struct nsm_resp_tlv_head *head;
Packit Service d8d8ac
	struct nsm_resp_tlv_foot *foot;
Packit Service d8d8ac
	struct timePropertiesDS *tp;
Packit Service d8d8ac
	struct PortAddress *paddr;
Packit Service d8d8ac
	struct currentDS cds;
Packit Service d8d8ac
	struct parentDS *pds;
Packit Service d8d8ac
	struct Timestamp ts;
Packit Service d8d8ac
	unsigned char *ptr;
Packit Service d8d8ac
	int64_t offset;
Packit Service d8d8ac
Packit Service d8d8ac
	if (!nsm->nsm_delay_req) {
Packit Service d8d8ac
		return;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (msg->header.sequenceId !=
Packit Service d8d8ac
	    ntohs(nsm->nsm_delay_req->header.sequenceId)) {
Packit Service d8d8ac
		return;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (!msg_unicast(msg)) {
Packit Service d8d8ac
		return;
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	switch (msg_type(msg)) {
Packit Service d8d8ac
	case SYNC:
Packit Service d8d8ac
		if (!nsm->nsm_sync) {
Packit Service d8d8ac
			nsm->nsm_sync = msg;
Packit Service d8d8ac
			msg_get(msg);
Packit Service d8d8ac
		}
Packit Service d8d8ac
		break;
Packit Service d8d8ac
	case FOLLOW_UP:
Packit Service d8d8ac
		if (!nsm->nsm_fup) {
Packit Service d8d8ac
			nsm->nsm_fup = msg;
Packit Service d8d8ac
			msg_get(msg);
Packit Service d8d8ac
		}
Packit Service d8d8ac
		break;
Packit Service d8d8ac
	case DELAY_RESP:
Packit Service d8d8ac
		if (!nsm->nsm_delay_resp) {
Packit Service d8d8ac
			nsm->nsm_delay_resp = msg;
Packit Service d8d8ac
			msg_get(msg);
Packit Service d8d8ac
		}
Packit Service d8d8ac
		break;
Packit Service d8d8ac
	case DELAY_REQ:
Packit Service d8d8ac
	case PDELAY_REQ:
Packit Service d8d8ac
	case PDELAY_RESP:
Packit Service d8d8ac
	case PDELAY_RESP_FOLLOW_UP:
Packit Service d8d8ac
	case ANNOUNCE:
Packit Service d8d8ac
	case SIGNALING:
Packit Service d8d8ac
	case MANAGEMENT:
Packit Service d8d8ac
		return;
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	if (!nsm_complete(nsm)) {
Packit Service d8d8ac
		return;
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	head = (struct nsm_resp_tlv_head *) nsm->nsm_delay_resp->delay_resp.suffix;
Packit Service d8d8ac
	paddr = &head->parent_addr;
Packit Service d8d8ac
Packit Service d8d8ac
	ptr = (unsigned char *) head;
Packit Service d8d8ac
	ptr += sizeof(*head) + paddr->addressLength;
Packit Service d8d8ac
	foot = (struct nsm_resp_tlv_foot *) ptr;
Packit Service d8d8ac
Packit Service d8d8ac
	pds = &foot->parent;
Packit Service d8d8ac
	memcpy(&cds, &foot->current, sizeof(cds));
Packit Service d8d8ac
	tp = &foot->timeprop;
Packit Service d8d8ac
	memcpy(&ts, &foot->lastsync, sizeof(ts));
Packit Service d8d8ac
Packit Service d8d8ac
	offset = nsm_compute_offset(nsm->tsproc, nsm->nsm_sync, nsm->nsm_fup,
Packit Service d8d8ac
				    nsm->nsm_delay_req, nsm->nsm_delay_resp);
Packit Service d8d8ac
Packit Service d8d8ac
	fprintf(fp, "NSM MEASUREMENT COMPLETE"
Packit Service d8d8ac
		IFMT "offset                                %" PRId64
Packit Service d8d8ac
		IFMT "portState                             %s"
Packit Service d8d8ac
		IFMT "parentPortAddress                     %hu %s\n",
Packit Service d8d8ac
		offset,
Packit Service d8d8ac
		ps_str[head->port_state],
Packit Service d8d8ac
		head->parent_addr.networkProtocol,
Packit Service d8d8ac
		portaddr2str(&head->parent_addr));
Packit Service d8d8ac
	fprintf(fp, "\tparentDataset"
Packit Service d8d8ac
		IFMT "parentPortIdentity                    %s"
Packit Service d8d8ac
		IFMT "parentStats                           %hhu"
Packit Service d8d8ac
		IFMT "observedParentOffsetScaledLogVariance 0x%04hx"
Packit Service d8d8ac
		IFMT "observedParentClockPhaseChangeRate    0x%08x"
Packit Service d8d8ac
		IFMT "grandmasterPriority1                  %hhu"
Packit Service d8d8ac
		IFMT "gm.ClockClass                         %hhu"
Packit Service d8d8ac
		IFMT "gm.ClockAccuracy                      0x%02hhx"
Packit Service d8d8ac
		IFMT "gm.OffsetScaledLogVariance            0x%04hx"
Packit Service d8d8ac
		IFMT "grandmasterPriority2                  %hhu"
Packit Service d8d8ac
		IFMT "grandmasterIdentity                   %s\n",
Packit Service d8d8ac
		pid2str(&pds->parentPortIdentity),
Packit Service d8d8ac
		pds->parentStats,
Packit Service d8d8ac
		pds->observedParentOffsetScaledLogVariance,
Packit Service d8d8ac
		pds->observedParentClockPhaseChangeRate,
Packit Service d8d8ac
		pds->grandmasterPriority1,
Packit Service d8d8ac
		pds->grandmasterClockQuality.clockClass,
Packit Service d8d8ac
		pds->grandmasterClockQuality.clockAccuracy,
Packit Service d8d8ac
		pds->grandmasterClockQuality.offsetScaledLogVariance,
Packit Service d8d8ac
		pds->grandmasterPriority2,
Packit Service d8d8ac
		cid2str(&pds->grandmasterIdentity));
Packit Service d8d8ac
	fprintf(fp, "\tcurrentDataset"
Packit Service d8d8ac
		IFMT "stepsRemoved                          %hd"
Packit Service d8d8ac
		IFMT "offsetFromMaster                      %.1f"
Packit Service d8d8ac
		IFMT "meanPathDelay                         %.1f\n",
Packit Service d8d8ac
		cds.stepsRemoved, cds.offsetFromMaster / 65536.0,
Packit Service d8d8ac
		cds.meanPathDelay / 65536.0);
Packit Service d8d8ac
	fprintf(fp, "\ttimePropertiesDataset"
Packit Service d8d8ac
		IFMT "currentUtcOffset                      %hd"
Packit Service d8d8ac
		IFMT "leap61                                %d"
Packit Service d8d8ac
		IFMT "leap59                                %d"
Packit Service d8d8ac
		IFMT "currentUtcOffsetValid                 %d"
Packit Service d8d8ac
		IFMT "ptpTimescale                          %d"
Packit Service d8d8ac
		IFMT "timeTraceable                         %d"
Packit Service d8d8ac
		IFMT "frequencyTraceable                    %d"
Packit Service d8d8ac
		IFMT "timeSource                            0x%02hhx\n",
Packit Service d8d8ac
		tp->currentUtcOffset,
Packit Service d8d8ac
		tp->flags & LEAP_61 ? 1 : 0,
Packit Service d8d8ac
		tp->flags & LEAP_59 ? 1 : 0,
Packit Service d8d8ac
		tp->flags & UTC_OFF_VALID ? 1 : 0,
Packit Service d8d8ac
		tp->flags & PTP_TIMESCALE ? 1 : 0,
Packit Service d8d8ac
		tp->flags & TIME_TRACEABLE ? 1 : 0,
Packit Service d8d8ac
		tp->flags & FREQ_TRACEABLE ? 1 : 0,
Packit Service d8d8ac
		tp->timeSource);
Packit Service d8d8ac
	fprintf(fp, "\tlastSyncTimestamp    %" PRId64 ".%09u\n",
Packit Service d8d8ac
		((uint64_t)ts.seconds_lsb) | (((uint64_t)ts.seconds_msb) << 32),
Packit Service d8d8ac
		ts.nanoseconds);
Packit Service d8d8ac
Packit Service d8d8ac
	fflush(fp);
Packit Service d8d8ac
	nsm_reset(nsm);
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
static void nsm_help(FILE *fp)
Packit Service d8d8ac
{
Packit Service d8d8ac
	fprintf(fp, "\tSend a NetSync Monitor request to a specific port address:\n");
Packit Service d8d8ac
	fprintf(fp, "\n");
Packit Service d8d8ac
	fprintf(fp, "\tNSM 111.222.333.444\n");
Packit Service d8d8ac
	fprintf(fp, "\tNSM aa:bb:cc:dd:ee:ff\n");
Packit Service d8d8ac
	fprintf(fp, "\n");
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
static int nsm_open(struct nsm *nsm, struct config *cfg)
Packit Service d8d8ac
{
Packit Service d8d8ac
	enum transport_type transport;
Packit Service d8d8ac
	struct interface *iface;
Packit Service d8d8ac
	const char *name;
Packit Service d8d8ac
	int count = 0;
Packit Service d8d8ac
Packit Service d8d8ac
	STAILQ_FOREACH(iface, &cfg->interfaces, list) {
Packit Service d8d8ac
		rtnl_get_ts_device(iface->name, iface->ts_label);
Packit Service d8d8ac
		if (iface->ts_label[0] == '\0') {
Packit Service d8d8ac
			strncpy(iface->ts_label, iface->name, MAX_IFNAME_SIZE);
Packit Service d8d8ac
		}
Packit Service d8d8ac
		count++;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (count != 1) {
Packit Service d8d8ac
		pr_err("need exactly one interface");
Packit Service d8d8ac
		return -1;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	iface = STAILQ_FIRST(&cfg->interfaces);
Packit Service d8d8ac
	nsm->name = name = iface->name;
Packit Service d8d8ac
	nsm->cfg = cfg;
Packit Service d8d8ac
Packit Service d8d8ac
	transport = config_get_int(cfg, name, "network_transport");
Packit Service d8d8ac
Packit Service d8d8ac
	if (generate_clock_identity(&nsm->port_identity.clockIdentity, name)) {
Packit Service d8d8ac
		pr_err("failed to generate a clock identity");
Packit Service d8d8ac
		return -1;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	nsm->port_identity.portNumber = 1;
Packit Service d8d8ac
Packit Service d8d8ac
	nsm->tsproc = tsproc_create(TSPROC_RAW, FILTER_MOVING_AVERAGE, 10);
Packit Service d8d8ac
	if (!nsm->tsproc) {
Packit Service d8d8ac
		pr_err("failed to create time stamp processor");
Packit Service d8d8ac
		goto no_tsproc;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	nsm->trp = transport_create(cfg, transport);
Packit Service d8d8ac
	if (!nsm->trp) {
Packit Service d8d8ac
		pr_err("failed to create transport");
Packit Service d8d8ac
		goto no_trans;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (transport_open(nsm->trp, iface, &nsm->fda,
Packit Service d8d8ac
			   config_get_int(cfg, NULL, "time_stamping"))) {
Packit Service d8d8ac
		pr_err("failed to open transport");
Packit Service d8d8ac
		goto open_failed;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	return 0;
Packit Service d8d8ac
Packit Service d8d8ac
open_failed:
Packit Service d8d8ac
	transport_destroy(nsm->trp);
Packit Service d8d8ac
no_trans:
Packit Service d8d8ac
	tsproc_destroy(nsm->tsproc);
Packit Service d8d8ac
no_tsproc:
Packit Service d8d8ac
	return -1;
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
static struct ptp_message *nsm_recv(struct nsm *nsm, int fd)
Packit Service d8d8ac
{
Packit Service d8d8ac
	struct ptp_message *msg;
Packit Service d8d8ac
	int cnt, err;
Packit Service d8d8ac
Packit Service d8d8ac
	msg = msg_allocate();
Packit Service d8d8ac
	if (!msg) {
Packit Service d8d8ac
		pr_err("low memory");
Packit Service d8d8ac
		return NULL;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	msg->hwts.type = config_get_int(nsm->cfg, NULL, "time_stamping");
Packit Service d8d8ac
Packit Service d8d8ac
	cnt = transport_recv(nsm->trp, fd, msg);
Packit Service d8d8ac
	if (cnt <= 0) {
Packit Service d8d8ac
		pr_err("recv message failed");
Packit Service d8d8ac
		goto failed;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	err = msg_post_recv(msg, cnt);
Packit Service d8d8ac
	if (err) {
Packit Service d8d8ac
		switch (err) {
Packit Service d8d8ac
		case -EBADMSG:
Packit Service d8d8ac
			pr_err("bad message");
Packit Service d8d8ac
			break;
Packit Service d8d8ac
		case -EPROTO:
Packit Service d8d8ac
			pr_debug("ignoring message");
Packit Service d8d8ac
			break;
Packit Service d8d8ac
		}
Packit Service d8d8ac
		goto failed;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (msg_sots_missing(msg)) {
Packit Service d8d8ac
		pr_err("received %s without timestamp",
Packit Service d8d8ac
		       msg_type_string(msg_type(msg)));
Packit Service d8d8ac
		goto failed;
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	return msg;
Packit Service d8d8ac
failed:
Packit Service d8d8ac
	msg_put(msg);
Packit Service d8d8ac
	return NULL;
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
static int nsm_request(struct nsm *nsm, char *target)
Packit Service d8d8ac
{
Packit Service d8d8ac
	enum transport_type type = transport_type(nsm->trp);
Packit Service d8d8ac
	UInteger8 transportSpecific;
Packit Service d8d8ac
	struct ptp_message *msg;
Packit Service d8d8ac
	struct tlv_extra *extra;
Packit Service d8d8ac
	Integer64 asymmetry;
Packit Service d8d8ac
	struct address dst;
Packit Service d8d8ac
	int cnt, err;
Packit Service d8d8ac
Packit Service d8d8ac
	if (str2addr(type, target, &dst)) {
Packit Service d8d8ac
		return -1;
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	msg = msg_allocate();
Packit Service d8d8ac
	if (!msg) {
Packit Service d8d8ac
		return -1;
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	transportSpecific = config_get_int(nsm->cfg, nsm->name, "transportSpecific");
Packit Service d8d8ac
	transportSpecific <<= 4;
Packit Service d8d8ac
Packit Service d8d8ac
	asymmetry = config_get_int(nsm->cfg, nsm->name, "delayAsymmetry");
Packit Service d8d8ac
	asymmetry <<= 16;
Packit Service d8d8ac
Packit Service d8d8ac
	msg->hwts.type = config_get_int(nsm->cfg, NULL, "time_stamping");
Packit Service d8d8ac
Packit Service d8d8ac
	msg->header.tsmt               = DELAY_REQ | transportSpecific;
Packit Service d8d8ac
	msg->header.ver                = PTP_VERSION;
Packit Service d8d8ac
	msg->header.messageLength      = sizeof(struct delay_req_msg);
Packit Service d8d8ac
	msg->header.domainNumber       = config_get_int(nsm->cfg, NULL, "domainNumber");
Packit Service d8d8ac
	msg->header.correction         = -asymmetry;
Packit Service d8d8ac
	msg->header.sourcePortIdentity = nsm->port_identity;
Packit Service d8d8ac
	msg->header.sequenceId         = nsm->sequence_id++;
Packit Service d8d8ac
	msg->header.control            = CTL_DELAY_REQ;
Packit Service d8d8ac
	msg->header.logMessageInterval = 0x7f;
Packit Service d8d8ac
Packit Service d8d8ac
	msg->address = dst;
Packit Service d8d8ac
	msg->header.flagField[0] |= UNICAST;
Packit Service d8d8ac
Packit Service d8d8ac
	extra = msg_tlv_append(msg, sizeof(struct TLV));
Packit Service d8d8ac
	if (!extra) {
Packit Service d8d8ac
		msg_put(msg);
Packit Service d8d8ac
		return -ENOMEM;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	extra->tlv->type = TLV_PTPMON_REQ;
Packit Service d8d8ac
	extra->tlv->length = 0;
Packit Service d8d8ac
Packit Service d8d8ac
	err = msg_pre_send(msg);
Packit Service d8d8ac
	if (err) {
Packit Service d8d8ac
		pr_err("msg_pre_send failed");
Packit Service d8d8ac
		goto out;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	cnt = transport_sendto(nsm->trp, &nsm->fda, TRANS_EVENT, msg);
Packit Service d8d8ac
	if (cnt <= 0) {
Packit Service d8d8ac
		pr_err("transport_sendto failed");
Packit Service d8d8ac
		err = -1;
Packit Service d8d8ac
		goto out;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (msg_sots_missing(msg)) {
Packit Service d8d8ac
		pr_err("missing timestamp on transmitted delay request");
Packit Service d8d8ac
		err = -1;
Packit Service d8d8ac
		goto out;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	nsm_reset(nsm);
Packit Service d8d8ac
	nsm->nsm_delay_req = msg;
Packit Service d8d8ac
	return 0;
Packit Service d8d8ac
out:
Packit Service d8d8ac
	msg_put(msg);
Packit Service d8d8ac
	return err;
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
static void nsm_reset(struct nsm *nsm)
Packit Service d8d8ac
{
Packit Service d8d8ac
	if (nsm->nsm_delay_req) {
Packit Service d8d8ac
		msg_put(nsm->nsm_delay_req);
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (nsm->nsm_delay_resp) {
Packit Service d8d8ac
		msg_put(nsm->nsm_delay_resp);
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (nsm->nsm_sync) {
Packit Service d8d8ac
		msg_put(nsm->nsm_sync);
Packit Service d8d8ac
	}
Packit Service d8d8ac
	if (nsm->nsm_fup) {
Packit Service d8d8ac
		msg_put(nsm->nsm_fup);
Packit Service d8d8ac
	}
Packit Service d8d8ac
	nsm->nsm_delay_req = NULL;
Packit Service d8d8ac
	nsm->nsm_delay_resp = NULL;
Packit Service d8d8ac
	nsm->nsm_sync = NULL;
Packit Service d8d8ac
	nsm->nsm_fup = NULL;
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
static void usage(char *progname)
Packit Service d8d8ac
{
Packit Service d8d8ac
	fprintf(stderr,
Packit Service d8d8ac
		"\nusage: %s [options]\n\n"
Packit Service d8d8ac
		" -f [file] read configuration from 'file'\n"
Packit Service d8d8ac
		" -h        prints this message and exits\n"
Packit Service d8d8ac
		" -i [dev]  interface device to use\n"
Packit Service d8d8ac
		" -v        prints the software version and exits\n"
Packit Service d8d8ac
		"\n",
Packit Service d8d8ac
		progname);
Packit Service d8d8ac
}
Packit Service d8d8ac
Packit Service d8d8ac
int main(int argc, char *argv[])
Packit Service d8d8ac
{
Packit Service d8d8ac
	int batch_mode = 0, c, cnt, err = 0, index, length, tmo = -1;
Packit Service d8d8ac
	char *cmd = NULL, *config = NULL, line[1024], *progname;
Packit Service d8d8ac
	struct pollfd pollfd[NSM_NFD];
Packit Service d8d8ac
	struct nsm *nsm = &the_nsm;
Packit Service d8d8ac
	struct ptp_message *msg;
Packit Service d8d8ac
	struct option *opts;
Packit Service d8d8ac
	struct config *cfg;
Packit Service d8d8ac
Packit Service d8d8ac
	if (handle_term_signals()) {
Packit Service d8d8ac
		return -1;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	cfg = config_create();
Packit Service d8d8ac
	if (!cfg) {
Packit Service d8d8ac
		return -1;
Packit Service d8d8ac
	}
Packit Service d8d8ac
	opts = config_long_options(cfg);
Packit Service d8d8ac
	print_set_verbose(1);
Packit Service d8d8ac
	print_set_syslog(0);
Packit Service d8d8ac
Packit Service d8d8ac
	/* Process the command line arguments. */
Packit Service d8d8ac
	progname = strrchr(argv[0], '/');
Packit Service d8d8ac
	progname = progname ? 1+progname : argv[0];
Packit Service d8d8ac
	while (EOF != (c = getopt_long(argc, argv, "f:hi:v", opts, &index))) {
Packit Service d8d8ac
		switch (c) {
Packit Service d8d8ac
		case 0:
Packit Service d8d8ac
			if (config_parse_option(cfg, opts[index].name, optarg)) {
Packit Service d8d8ac
				config_destroy(cfg);
Packit Service d8d8ac
				return -1;
Packit Service d8d8ac
			}
Packit Service d8d8ac
			break;
Packit Service d8d8ac
		case 'f':
Packit Service d8d8ac
			config = optarg;
Packit Service d8d8ac
			break;
Packit Service d8d8ac
		case 'i':
Packit Service d8d8ac
			if (!config_create_interface(optarg, cfg)) {
Packit Service d8d8ac
				config_destroy(cfg);
Packit Service d8d8ac
				return -1;
Packit Service d8d8ac
			}
Packit Service d8d8ac
			break;
Packit Service d8d8ac
		case 'v':
Packit Service d8d8ac
			version_show(stdout);
Packit Service d8d8ac
			config_destroy(cfg);
Packit Service d8d8ac
			return 0;
Packit Service d8d8ac
		case 'h':
Packit Service d8d8ac
			usage(progname);
Packit Service d8d8ac
			config_destroy(cfg);
Packit Service d8d8ac
			return 0;
Packit Service d8d8ac
		case '?':
Packit Service d8d8ac
		default:
Packit Service d8d8ac
			usage(progname);
Packit Service d8d8ac
			config_destroy(cfg);
Packit Service d8d8ac
			return -1;
Packit Service d8d8ac
		}
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	print_set_syslog(0);
Packit Service d8d8ac
	print_set_verbose(1);
Packit Service d8d8ac
Packit Service d8d8ac
	if (config && (err = config_read(config, cfg))) {
Packit Service d8d8ac
		goto out;
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	print_set_progname(progname);
Packit Service d8d8ac
	print_set_tag(config_get_string(cfg, NULL, "message_tag"));
Packit Service d8d8ac
	print_set_level(config_get_int(cfg, NULL, "logging_level"));
Packit Service d8d8ac
Packit Service d8d8ac
	err = nsm_open(nsm, cfg);
Packit Service d8d8ac
	if (err) {
Packit Service d8d8ac
		goto out;
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	if (optind < argc) {
Packit Service d8d8ac
		batch_mode = 1;
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	pollfd[0].fd = nsm->fda.fd[0];
Packit Service d8d8ac
	pollfd[1].fd = nsm->fda.fd[1];
Packit Service d8d8ac
	pollfd[2].fd = batch_mode ? -1 : STDIN_FILENO;
Packit Service d8d8ac
	pollfd[0].events = POLLIN | POLLPRI;
Packit Service d8d8ac
	pollfd[1].events = POLLIN | POLLPRI;
Packit Service d8d8ac
	pollfd[2].events = batch_mode ? 0 : POLLIN | POLLPRI;
Packit Service d8d8ac
Packit Service d8d8ac
	while (is_running()) {
Packit Service d8d8ac
		if (batch_mode) {
Packit Service d8d8ac
			if (optind < argc && !nsm->nsm_delay_req) {
Packit Service d8d8ac
				cmd = argv[optind++];
Packit Service d8d8ac
				if (nsm_command(nsm, cmd)) {
Packit Service d8d8ac
					pr_err("command failed");
Packit Service d8d8ac
					continue;
Packit Service d8d8ac
				}
Packit Service d8d8ac
			}
Packit Service d8d8ac
			/* Wait a bit for any outstanding replies. */
Packit Service d8d8ac
			tmo = 100;
Packit Service d8d8ac
		}
Packit Service d8d8ac
Packit Service d8d8ac
		cnt = poll(pollfd, NSM_NFD, tmo);
Packit Service d8d8ac
		if (cnt < 0) {
Packit Service d8d8ac
			if (EINTR == errno) {
Packit Service d8d8ac
				continue;
Packit Service d8d8ac
			} else {
Packit Service d8d8ac
				pr_emerg("poll failed");
Packit Service d8d8ac
				err = -1;
Packit Service d8d8ac
				break;
Packit Service d8d8ac
			}
Packit Service d8d8ac
		} else if (!cnt && optind < argc) {
Packit Service d8d8ac
			/* For batch mode. No response received from target node,
Packit Service d8d8ac
			 * continue with next command. */
Packit Service d8d8ac
			nsm_reset(nsm);
Packit Service d8d8ac
			continue;
Packit Service d8d8ac
		} else if (!cnt) {
Packit Service d8d8ac
			break;
Packit Service d8d8ac
		}
Packit Service d8d8ac
		if (pollfd[2].revents & POLLHUP) {
Packit Service d8d8ac
			if (tmo == -1) {
Packit Service d8d8ac
				/* Wait a bit longer for outstanding replies. */
Packit Service d8d8ac
				tmo = 100;
Packit Service d8d8ac
				pollfd[2].fd = -1;
Packit Service d8d8ac
				pollfd[2].events = 0;
Packit Service d8d8ac
			} else {
Packit Service d8d8ac
				break;
Packit Service d8d8ac
			}
Packit Service d8d8ac
		}
Packit Service d8d8ac
		if (pollfd[2].revents & (POLLIN|POLLPRI)) {
Packit Service d8d8ac
			if (!fgets(line, sizeof(line), stdin)) {
Packit Service d8d8ac
				break;
Packit Service d8d8ac
			}
Packit Service d8d8ac
			length = strlen(line);
Packit Service d8d8ac
			if (length < 2) {
Packit Service d8d8ac
				continue;
Packit Service d8d8ac
			}
Packit Service d8d8ac
			line[length - 1] = 0;
Packit Service d8d8ac
			cmd = line;
Packit Service d8d8ac
			if (nsm_command(nsm, cmd)) {
Packit Service d8d8ac
				pr_err("command failed");
Packit Service d8d8ac
			}
Packit Service d8d8ac
		}
Packit Service d8d8ac
		if (pollfd[0].revents & (POLLIN|POLLPRI)) {
Packit Service d8d8ac
			msg = nsm_recv(nsm, pollfd[0].fd);
Packit Service d8d8ac
			if (msg) {
Packit Service d8d8ac
				nsm_handle_msg(nsm, msg, stdout);
Packit Service d8d8ac
				msg_put(msg);
Packit Service d8d8ac
			}
Packit Service d8d8ac
		}
Packit Service d8d8ac
		if (pollfd[1].revents & (POLLIN|POLLPRI)) {
Packit Service d8d8ac
			msg = nsm_recv(nsm, pollfd[1].fd);
Packit Service d8d8ac
			if (msg) {
Packit Service d8d8ac
				nsm_handle_msg(nsm, msg, stdout);
Packit Service d8d8ac
				msg_put(msg);
Packit Service d8d8ac
			}
Packit Service d8d8ac
		}
Packit Service d8d8ac
	}
Packit Service d8d8ac
Packit Service d8d8ac
	nsm_close(nsm);
Packit Service d8d8ac
out:
Packit Service d8d8ac
	msg_cleanup();
Packit Service d8d8ac
	config_destroy(cfg);
Packit Service d8d8ac
	return err;
Packit Service d8d8ac
}