Blame nsm.c

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