Blame tc.c

Packit 9c3e7e
/**
Packit 9c3e7e
 * @file tc.c
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-1335 USA.
Packit 9c3e7e
 */
Packit 9c3e7e
#include <stdlib.h>
Packit 9c3e7e
Packit 9c3e7e
#include "port.h"
Packit 9c3e7e
#include "print.h"
Packit 9c3e7e
#include "tc.h"
Packit 9c3e7e
#include "tmv.h"
Packit 9c3e7e
Packit 9c3e7e
enum tc_match {
Packit 9c3e7e
	TC_MISMATCH,
Packit 9c3e7e
	TC_SYNC_FUP,
Packit 9c3e7e
	TC_FUP_SYNC,
Packit 9c3e7e
	TC_DELAY_REQRESP,
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
static TAILQ_HEAD(tc_pool, tc_txd) tc_pool = TAILQ_HEAD_INITIALIZER(tc_pool);
Packit 9c3e7e
Packit 9c3e7e
static int tc_match_delay(int ingress_port, struct ptp_message *resp,
Packit 9c3e7e
			  struct tc_txd *txd);
Packit 9c3e7e
static int tc_match_syfup(int ingress_port, struct ptp_message *msg,
Packit 9c3e7e
			  struct tc_txd *txd);
Packit 9c3e7e
static void tc_recycle(struct tc_txd *txd);
Packit 9c3e7e
Packit 9c3e7e
static struct tc_txd *tc_allocate(void)
Packit 9c3e7e
{
Packit 9c3e7e
	struct tc_txd *txd = TAILQ_FIRST(&tc_pool);
Packit 9c3e7e
Packit 9c3e7e
	if (txd) {
Packit 9c3e7e
		TAILQ_REMOVE(&tc_pool, txd, list);
Packit 9c3e7e
		memset(txd, 0, sizeof(*txd));
Packit 9c3e7e
		return txd;
Packit 9c3e7e
	}
Packit 9c3e7e
	txd = calloc(1, sizeof(*txd));
Packit 9c3e7e
	return txd;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int tc_blocked(struct port *q, struct port *p, struct ptp_message *m)
Packit 9c3e7e
{
Packit 9c3e7e
	enum port_state s;
Packit 9c3e7e
Packit 9c3e7e
	if (q == p) {
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (portnum(p) == 0) {
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (!q->tc_spanning_tree) {
Packit 9c3e7e
		return 0;
Packit 9c3e7e
	}
Packit 9c3e7e
	/* Forward frames in the wrong domain unconditionally. */
Packit 9c3e7e
	if (m->header.domainNumber != clock_domain_number(p->clock)) {
Packit 9c3e7e
		return 0;
Packit 9c3e7e
	}
Packit 9c3e7e
	/* Ingress state */
Packit 9c3e7e
	s = port_state(q);
Packit 9c3e7e
	switch (s) {
Packit 9c3e7e
	case PS_INITIALIZING:
Packit 9c3e7e
	case PS_FAULTY:
Packit 9c3e7e
	case PS_DISABLED:
Packit 9c3e7e
	case PS_LISTENING:
Packit 9c3e7e
	case PS_PRE_MASTER:
Packit 9c3e7e
	case PS_PASSIVE:
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	case PS_MASTER:
Packit 9c3e7e
	case PS_GRAND_MASTER:
Packit 9c3e7e
		/* Delay_Req swims against the stream. */
Packit 9c3e7e
		if (msg_type(m) != DELAY_REQ) {
Packit 9c3e7e
			return 1;
Packit 9c3e7e
		}
Packit 9c3e7e
		break;
Packit 9c3e7e
	case PS_UNCALIBRATED:
Packit 9c3e7e
	case PS_SLAVE:
Packit 9c3e7e
		break;
Packit 9c3e7e
	}
Packit 9c3e7e
	/* Egress state */
Packit 9c3e7e
	s = port_state(p);
Packit 9c3e7e
	switch (s) {
Packit 9c3e7e
	case PS_INITIALIZING:
Packit 9c3e7e
	case PS_FAULTY:
Packit 9c3e7e
	case PS_DISABLED:
Packit 9c3e7e
	case PS_LISTENING:
Packit 9c3e7e
	case PS_PRE_MASTER:
Packit 9c3e7e
	case PS_PASSIVE:
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	case PS_UNCALIBRATED:
Packit 9c3e7e
	case PS_SLAVE:
Packit 9c3e7e
		/* Delay_Req swims against the stream. */
Packit 9c3e7e
		if (msg_type(m) != DELAY_REQ) {
Packit 9c3e7e
			return 1;
Packit 9c3e7e
		}
Packit 9c3e7e
		break;
Packit 9c3e7e
	case PS_MASTER:
Packit 9c3e7e
	case PS_GRAND_MASTER:
Packit 9c3e7e
		/* No use forwarding Delay_Req out the wrong port. */
Packit 9c3e7e
		if (msg_type(m) == DELAY_REQ) {
Packit 9c3e7e
			return 1;
Packit 9c3e7e
		}
Packit 9c3e7e
		break;
Packit 9c3e7e
	}
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void tc_complete_request(struct port *q, struct port *p,
Packit 9c3e7e
				struct ptp_message *req, tmv_t residence)
Packit 9c3e7e
{
Packit 9c3e7e
	struct tc_txd *txd = tc_allocate();
Packit 9c3e7e
	if (!txd) {
Packit 9c3e7e
		port_dispatch(p, EV_FAULT_DETECTED, 0);
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
#ifdef DEBUG
Packit 9c3e7e
	pr_err("stash delay request from port %hd to %hd seqid %hu residence %lu",
Packit 9c3e7e
	       portnum(q), portnum(p), ntohs(req->header.sequenceId),
Packit 9c3e7e
	       (unsigned long) tmv_to_nanoseconds(residence));
Packit 9c3e7e
#endif
Packit 9c3e7e
	msg_get(req);
Packit 9c3e7e
	txd->msg = req;
Packit 9c3e7e
	txd->residence = residence;
Packit 9c3e7e
	txd->ingress_port = portnum(q);
Packit 9c3e7e
	TAILQ_INSERT_TAIL(&p->tc_transmitted, txd, list);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void tc_complete_response(struct port *q, struct port *p,
Packit 9c3e7e
				 struct ptp_message *resp, tmv_t residence)
Packit 9c3e7e
{
Packit 9c3e7e
	enum tc_match type = TC_MISMATCH;
Packit 9c3e7e
	struct tc_txd *txd;
Packit 9c3e7e
	Integer64 c1, c2;
Packit 9c3e7e
	int cnt;
Packit 9c3e7e
Packit 9c3e7e
#ifdef DEBUG
Packit 9c3e7e
	pr_err("complete delay response from port %hd to %hd seqid %hu",
Packit 9c3e7e
	       portnum(q), portnum(p), ntohs(resp->header.sequenceId));
Packit 9c3e7e
#endif
Packit 9c3e7e
	TAILQ_FOREACH(txd, &q->tc_transmitted, list) {
Packit 9c3e7e
		type = tc_match_delay(portnum(p), resp, txd);
Packit 9c3e7e
		if (type == TC_DELAY_REQRESP) {
Packit 9c3e7e
			residence = txd->residence;
Packit 9c3e7e
			break;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
	if (type != TC_DELAY_REQRESP) {
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
	c1 = net2host64(resp->header.correction);
Packit 9c3e7e
	c2 = c1 + tmv_to_TimeInterval(residence);
Packit 9c3e7e
	resp->header.correction = host2net64(c2);
Packit 9c3e7e
	cnt = transport_send(p->trp, &p->fda, TRANS_GENERAL, resp);
Packit 9c3e7e
	if (cnt <= 0) {
Packit 9c3e7e
		pr_err("tc failed to forward response on port %d", portnum(p));
Packit 9c3e7e
		port_dispatch(p, EV_FAULT_DETECTED, 0);
Packit 9c3e7e
	}
Packit 9c3e7e
	/* Restore original correction value for next egress port. */
Packit 9c3e7e
	resp->header.correction = host2net64(c1);
Packit 9c3e7e
	TAILQ_REMOVE(&q->tc_transmitted, txd, list);
Packit 9c3e7e
	msg_put(txd->msg);
Packit 9c3e7e
	tc_recycle(txd);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void tc_complete_syfup(struct port *q, struct port *p,
Packit 9c3e7e
			      struct ptp_message *msg, tmv_t residence)
Packit 9c3e7e
{
Packit 9c3e7e
	enum tc_match type = TC_MISMATCH;
Packit 9c3e7e
	struct ptp_message *fup;
Packit 9c3e7e
	struct tc_txd *txd;
Packit 9c3e7e
	Integer64 c1, c2;
Packit 9c3e7e
	int cnt;
Packit 9c3e7e
Packit 9c3e7e
	TAILQ_FOREACH(txd, &p->tc_transmitted, list) {
Packit 9c3e7e
		type = tc_match_syfup(portnum(q), msg, txd);
Packit 9c3e7e
		switch (type) {
Packit 9c3e7e
		case TC_MISMATCH:
Packit 9c3e7e
			break;
Packit 9c3e7e
		case TC_SYNC_FUP:
Packit 9c3e7e
			fup = msg;
Packit 9c3e7e
			residence = txd->residence;
Packit 9c3e7e
			break;
Packit 9c3e7e
		case TC_FUP_SYNC:
Packit 9c3e7e
			fup = txd->msg;
Packit 9c3e7e
			break;
Packit 9c3e7e
		case TC_DELAY_REQRESP:
Packit 9c3e7e
			pr_err("tc: unexpected match of delay request - sync!");
Packit 9c3e7e
			return;
Packit 9c3e7e
		}
Packit 9c3e7e
		if (type != TC_MISMATCH) {
Packit 9c3e7e
			break;
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (type == TC_MISMATCH) {
Packit 9c3e7e
		txd = tc_allocate();
Packit 9c3e7e
		if (!txd) {
Packit 9c3e7e
			port_dispatch(p, EV_FAULT_DETECTED, 0);
Packit 9c3e7e
			return;
Packit 9c3e7e
		}
Packit 9c3e7e
		msg_get(msg);
Packit 9c3e7e
		txd->msg = msg;
Packit 9c3e7e
		txd->residence = residence;
Packit 9c3e7e
		txd->ingress_port = portnum(q);
Packit 9c3e7e
		TAILQ_INSERT_TAIL(&p->tc_transmitted, txd, list);
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	c1 = net2host64(fup->header.correction);
Packit 9c3e7e
	c2 = c1 + tmv_to_TimeInterval(residence);
Packit 9c3e7e
	c2 += tmv_to_TimeInterval(q->peer_delay);
Packit 9c3e7e
	c2 += q->asymmetry;
Packit 9c3e7e
	fup->header.correction = host2net64(c2);
Packit 9c3e7e
	cnt = transport_send(p->trp, &p->fda, TRANS_GENERAL, fup);
Packit 9c3e7e
	if (cnt <= 0) {
Packit 9c3e7e
		pr_err("tc failed to forward follow up on port %d", portnum(p));
Packit 9c3e7e
		port_dispatch(p, EV_FAULT_DETECTED, 0);
Packit 9c3e7e
	}
Packit 9c3e7e
	/* Restore original correction value for next egress port. */
Packit 9c3e7e
	fup->header.correction = host2net64(c1);
Packit 9c3e7e
	TAILQ_REMOVE(&p->tc_transmitted, txd, list);
Packit 9c3e7e
	msg_put(txd->msg);
Packit 9c3e7e
	tc_recycle(txd);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void tc_complete(struct port *q, struct port *p,
Packit 9c3e7e
			struct ptp_message *msg, tmv_t residence)
Packit 9c3e7e
{
Packit 9c3e7e
	switch (msg_type(msg)) {
Packit 9c3e7e
	case SYNC:
Packit 9c3e7e
	case FOLLOW_UP:
Packit 9c3e7e
		tc_complete_syfup(q, p, msg, residence);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case DELAY_REQ:
Packit 9c3e7e
		tc_complete_request(q, p, msg, residence);
Packit 9c3e7e
		break;
Packit 9c3e7e
	case DELAY_RESP:
Packit 9c3e7e
		tc_complete_response(q, p, msg, residence);
Packit 9c3e7e
		break;
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int tc_current(struct ptp_message *m, struct timespec now)
Packit 9c3e7e
{
Packit 9c3e7e
	int64_t t1, t2, tmo;
Packit 9c3e7e
Packit 9c3e7e
	tmo = 1LL * NSEC2SEC;
Packit 9c3e7e
	t1 = m->ts.host.tv_sec * NSEC2SEC + m->ts.host.tv_nsec;
Packit 9c3e7e
	t2 = now.tv_sec * NSEC2SEC + now.tv_nsec;
Packit 9c3e7e
Packit 9c3e7e
	return t2 - t1 < tmo;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int tc_fwd_event(struct port *q, struct ptp_message *msg)
Packit 9c3e7e
{
Packit 9c3e7e
	tmv_t egress, ingress = msg->hwts.ts, residence;
Packit 9c3e7e
	struct port *p;
Packit 9c3e7e
	int cnt, err;
Packit 9c3e7e
	double rr;
Packit 9c3e7e
Packit 9c3e7e
	clock_gettime(CLOCK_MONOTONIC, &msg->ts.host);
Packit 9c3e7e
Packit 9c3e7e
	/* First send the event message out. */
Packit 9c3e7e
	for (p = clock_first_port(q->clock); p; p = LIST_NEXT(p, list)) {
Packit 9c3e7e
		if (tc_blocked(q, p, msg)) {
Packit 9c3e7e
			continue;
Packit 9c3e7e
		}
Packit 9c3e7e
		cnt = transport_send(p->trp, &p->fda, TRANS_DEFER_EVENT, msg);
Packit 9c3e7e
		if (cnt <= 0) {
Packit 9c3e7e
			pr_err("failed to forward event from port %hd to %hd",
Packit 9c3e7e
				portnum(q), portnum(p));
Packit 9c3e7e
			port_dispatch(p, EV_FAULT_DETECTED, 0);
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	/* Go back and gather the transmit time stamps. */
Packit 9c3e7e
	for (p = clock_first_port(q->clock); p; p = LIST_NEXT(p, list)) {
Packit 9c3e7e
		if (tc_blocked(q, p, msg)) {
Packit 9c3e7e
			continue;
Packit 9c3e7e
		}
Packit 9c3e7e
		err = transport_txts(&p->fda, msg);
Packit 9c3e7e
		if (err || !msg_sots_valid(msg)) {
Packit 9c3e7e
			pr_err("failed to fetch txts on port %hd to %hd event",
Packit 9c3e7e
				portnum(q), portnum(p));
Packit 9c3e7e
			port_dispatch(p, EV_FAULT_DETECTED, 0);
Packit 9c3e7e
			continue;
Packit 9c3e7e
		}
Packit 9c3e7e
		ts_add(&msg->hwts.ts, p->tx_timestamp_offset);
Packit 9c3e7e
		egress = msg->hwts.ts;
Packit 9c3e7e
		residence = tmv_sub(egress, ingress);
Packit 9c3e7e
		rr = clock_rate_ratio(q->clock);
Packit 9c3e7e
		if (rr != 1.0) {
Packit 9c3e7e
			residence = dbl_tmv(tmv_dbl(residence) * rr);
Packit 9c3e7e
		}
Packit 9c3e7e
		tc_complete(q, p, msg, residence);
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int tc_match_delay(int ingress_port, struct ptp_message *resp,
Packit 9c3e7e
			  struct tc_txd *txd)
Packit 9c3e7e
{
Packit 9c3e7e
	struct ptp_message *req = txd->msg;
Packit 9c3e7e
Packit 9c3e7e
	if (ingress_port != txd->ingress_port) {
Packit 9c3e7e
		return TC_MISMATCH;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (req->header.sequenceId != resp->header.sequenceId) {
Packit 9c3e7e
		return TC_MISMATCH;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (!pid_eq(&req->header.sourcePortIdentity,
Packit 9c3e7e
		    &resp->delay_resp.requestingPortIdentity)) {
Packit 9c3e7e
		return TC_MISMATCH;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (msg_type(req) == DELAY_REQ && msg_type(resp) == DELAY_RESP) {
Packit 9c3e7e
		return TC_DELAY_REQRESP;
Packit 9c3e7e
	}
Packit 9c3e7e
	return TC_MISMATCH;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int tc_match_syfup(int ingress_port, struct ptp_message *msg,
Packit 9c3e7e
			  struct tc_txd *txd)
Packit 9c3e7e
{
Packit 9c3e7e
	if (ingress_port != txd->ingress_port) {
Packit 9c3e7e
		return TC_MISMATCH;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (msg->header.sequenceId != txd->msg->header.sequenceId) {
Packit 9c3e7e
		return TC_MISMATCH;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (!source_pid_eq(msg, txd->msg)) {
Packit 9c3e7e
		return TC_MISMATCH;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (msg_type(txd->msg) == SYNC && msg_type(msg) == FOLLOW_UP) {
Packit 9c3e7e
		return TC_SYNC_FUP;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (msg_type(txd->msg) == FOLLOW_UP && msg_type(msg) == SYNC) {
Packit 9c3e7e
		return TC_FUP_SYNC;
Packit 9c3e7e
	}
Packit 9c3e7e
	return TC_MISMATCH;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void tc_recycle(struct tc_txd *txd)
Packit 9c3e7e
{
Packit 9c3e7e
	TAILQ_INSERT_HEAD(&tc_pool, txd, list);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/* public methods */
Packit 9c3e7e
Packit 9c3e7e
void tc_cleanup(void)
Packit 9c3e7e
{
Packit 9c3e7e
	struct tc_txd *txd;
Packit 9c3e7e
Packit 9c3e7e
	while ((txd = TAILQ_FIRST(&tc_pool)) != NULL) {
Packit 9c3e7e
		TAILQ_REMOVE(&tc_pool, txd, list);
Packit 9c3e7e
		free(txd);
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void tc_flush(struct port *q)
Packit 9c3e7e
{
Packit 9c3e7e
	struct tc_txd *txd;
Packit 9c3e7e
Packit 9c3e7e
	while ((txd = TAILQ_FIRST(&q->tc_transmitted)) != NULL) {
Packit 9c3e7e
		TAILQ_REMOVE(&q->tc_transmitted, txd, list);
Packit 9c3e7e
		msg_put(txd->msg);
Packit 9c3e7e
		tc_recycle(txd);
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int tc_forward(struct port *q, struct ptp_message *msg)
Packit 9c3e7e
{
Packit 9c3e7e
	uint16_t steps_removed;
Packit 9c3e7e
	struct port *p;
Packit 9c3e7e
	int cnt;
Packit 9c3e7e
Packit 9c3e7e
	if (q->tc_spanning_tree && msg_type(msg) == ANNOUNCE) {
Packit 9c3e7e
		steps_removed = ntohs(msg->announce.stepsRemoved);
Packit 9c3e7e
		msg->announce.stepsRemoved = htons(1 + steps_removed);
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	for (p = clock_first_port(q->clock); p; p = LIST_NEXT(p, list)) {
Packit 9c3e7e
		if (tc_blocked(q, p, msg)) {
Packit 9c3e7e
			continue;
Packit 9c3e7e
		}
Packit 9c3e7e
		cnt = transport_send(p->trp, &p->fda, TRANS_GENERAL, msg);
Packit 9c3e7e
		if (cnt <= 0) {
Packit 9c3e7e
			pr_err("tc failed to forward message on port %d",
Packit 9c3e7e
			       portnum(p));
Packit 9c3e7e
			port_dispatch(p, EV_FAULT_DETECTED, 0);
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int tc_fwd_folup(struct port *q, struct ptp_message *msg)
Packit 9c3e7e
{
Packit 9c3e7e
	struct port *p;
Packit 9c3e7e
Packit 9c3e7e
	clock_gettime(CLOCK_MONOTONIC, &msg->ts.host);
Packit 9c3e7e
Packit 9c3e7e
	for (p = clock_first_port(q->clock); p; p = LIST_NEXT(p, list)) {
Packit 9c3e7e
		if (tc_blocked(q, p, msg)) {
Packit 9c3e7e
			continue;
Packit 9c3e7e
		}
Packit 9c3e7e
		tc_complete(q, p, msg, tmv_zero());
Packit 9c3e7e
	}
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int tc_fwd_request(struct port *q, struct ptp_message *msg)
Packit 9c3e7e
{
Packit 9c3e7e
	return tc_fwd_event(q, msg);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int tc_fwd_response(struct port *q, struct ptp_message *msg)
Packit 9c3e7e
{
Packit 9c3e7e
	struct port *p;
Packit 9c3e7e
Packit 9c3e7e
	clock_gettime(CLOCK_MONOTONIC, &msg->ts.host);
Packit 9c3e7e
Packit 9c3e7e
	for (p = clock_first_port(q->clock); p; p = LIST_NEXT(p, list)) {
Packit 9c3e7e
		if (tc_blocked(q, p, msg)) {
Packit 9c3e7e
			continue;
Packit 9c3e7e
		}
Packit 9c3e7e
		tc_complete(q, p, msg, tmv_zero());
Packit 9c3e7e
	}
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int tc_fwd_sync(struct port *q, struct ptp_message *msg)
Packit 9c3e7e
{
Packit 9c3e7e
	struct ptp_message *fup = NULL;
Packit 9c3e7e
	int err;
Packit 9c3e7e
Packit 9c3e7e
	if (one_step(msg)) {
Packit 9c3e7e
		fup = msg_allocate();
Packit 9c3e7e
		if (!fup) {
Packit 9c3e7e
			return -1;
Packit 9c3e7e
		}
Packit 9c3e7e
		fup->header.tsmt               = FOLLOW_UP | (msg->header.tsmt & 0xf0);
Packit 9c3e7e
		fup->header.ver                = msg->header.ver;
Packit 9c3e7e
		fup->header.messageLength      = sizeof(struct follow_up_msg);
Packit 9c3e7e
		fup->header.domainNumber       = msg->header.domainNumber;
Packit 9c3e7e
		fup->header.sourcePortIdentity = msg->header.sourcePortIdentity;
Packit 9c3e7e
		fup->header.sequenceId         = msg->header.sequenceId;
Packit 9c3e7e
		fup->header.control            = CTL_FOLLOW_UP;
Packit 9c3e7e
		fup->header.logMessageInterval = msg->header.logMessageInterval;
Packit 9c3e7e
		fup->follow_up.preciseOriginTimestamp = msg->sync.originTimestamp;
Packit 9c3e7e
		msg->header.flagField[0]      |= TWO_STEP;
Packit 9c3e7e
	}
Packit 9c3e7e
	err = tc_fwd_event(q, msg);
Packit 9c3e7e
	if (err) {
Packit 9c3e7e
		return err;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (fup) {
Packit 9c3e7e
		err = tc_fwd_folup(q, fup);
Packit 9c3e7e
		msg_put(fup);
Packit 9c3e7e
	}
Packit 9c3e7e
	return err;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int tc_ignore(struct port *p, struct ptp_message *m)
Packit 9c3e7e
{
Packit 9c3e7e
	struct ClockIdentity c1, c2;
Packit 9c3e7e
Packit 9c3e7e
	if (p->match_transport_specific &&
Packit 9c3e7e
	    msg_transport_specific(m) != p->transportSpecific) {
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (pid_eq(&m->header.sourcePortIdentity, &p->portIdentity)) {
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (m->header.domainNumber != clock_domain_number(p->clock)) {
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	c1 = clock_identity(p->clock);
Packit 9c3e7e
	c2 = m->header.sourcePortIdentity.clockIdentity;
Packit 9c3e7e
Packit 9c3e7e
	if (cid_eq(&c1, &c2)) {
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	}
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void tc_prune(struct port *q)
Packit 9c3e7e
{
Packit 9c3e7e
	struct timespec now;
Packit 9c3e7e
	struct tc_txd *txd;
Packit 9c3e7e
Packit 9c3e7e
	clock_gettime(CLOCK_MONOTONIC, &now;;
Packit 9c3e7e
Packit 9c3e7e
	while ((txd = TAILQ_FIRST(&q->tc_transmitted)) != NULL) {
Packit 9c3e7e
		if (tc_current(txd->msg, now)) {
Packit 9c3e7e
			break;
Packit 9c3e7e
		}
Packit 9c3e7e
		TAILQ_REMOVE(&q->tc_transmitted, txd, list);
Packit 9c3e7e
		msg_put(txd->msg);
Packit 9c3e7e
		tc_recycle(txd);
Packit 9c3e7e
	}
Packit 9c3e7e
}