Blame unicast_service.c

Packit 9c3e7e
/**
Packit 9c3e7e
 * @file unicast_service.c
Packit 9c3e7e
 * @brief Unicast service
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
#include <sys/queue.h>
Packit 9c3e7e
#include <time.h>
Packit 9c3e7e
Packit 9c3e7e
#include "address.h"
Packit 9c3e7e
#include "clock.h"
Packit 9c3e7e
#include "missing.h"
Packit 9c3e7e
#include "port.h"
Packit 9c3e7e
#include "port_private.h"
Packit 9c3e7e
#include "pqueue.h"
Packit 9c3e7e
#include "print.h"
Packit 9c3e7e
#include "unicast_service.h"
Packit 9c3e7e
#include "util.h"
Packit 9c3e7e
Packit babef3
#define MIN_LOG_INTER_MESSAGE_PERIOD -7
Packit babef3
#define MAX_LOG_INTER_MESSAGE_PERIOD 16
Packit babef3
#define MAX_DURATION 3600
Packit 9c3e7e
#define QUEUE_LEN 16
Packit 9c3e7e
Packit 9c3e7e
struct unicast_client_address {
Packit 9c3e7e
	LIST_ENTRY(unicast_client_address) list;
Packit 9c3e7e
	struct PortIdentity portIdentity;
Packit 9c3e7e
	unsigned int message_types;
Packit 9c3e7e
	struct address addr;
Packit 9c3e7e
	time_t grant_tmo;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
struct unicast_service_interval {
Packit 9c3e7e
	LIST_HEAD(uca, unicast_client_address) clients;
Packit 9c3e7e
	LIST_ENTRY(unicast_service_interval) list;
Packit 9c3e7e
	struct timespec incr;
Packit 9c3e7e
	struct timespec tmo;
Packit 9c3e7e
	int log_period;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
struct unicast_service {
Packit 9c3e7e
	LIST_HEAD(usi, unicast_service_interval) intervals;
Packit 9c3e7e
	struct pqueue *queue;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
static struct timespec log_to_timespec(int log_seconds);
Packit 9c3e7e
static int timespec_compare(struct timespec *a, struct timespec *b);
Packit 9c3e7e
static void timespec_normalize(struct timespec *ts);
Packit 9c3e7e
Packit 9c3e7e
static int attach_grant(struct ptp_message *msg,
Packit 9c3e7e
			struct request_unicast_xmit_tlv *req,
Packit 9c3e7e
			int duration)
Packit 9c3e7e
{
Packit 9c3e7e
	struct grant_unicast_xmit_tlv *g;
Packit 9c3e7e
	struct tlv_extra *extra;
Packit 9c3e7e
Packit 9c3e7e
	extra = msg_tlv_append(msg, sizeof(*g));
Packit 9c3e7e
	if (!extra) {
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	g = (struct grant_unicast_xmit_tlv *) extra->tlv;
Packit 9c3e7e
	g->type = TLV_GRANT_UNICAST_TRANSMISSION;
Packit 9c3e7e
	g->length = sizeof(*g) - sizeof(g->type) - sizeof(g->length);
Packit 9c3e7e
	g->message_type = req->message_type;
Packit 9c3e7e
	g->logInterMessagePeriod = req->logInterMessagePeriod;
Packit 9c3e7e
	g->durationField = duration;
Packit 9c3e7e
	g->flags = GRANT_UNICAST_RENEWAL_INVITED;
Packit 9c3e7e
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int compare_timeout(void *ain, void *bin)
Packit 9c3e7e
{
Packit 9c3e7e
	struct unicast_service_interval *a, *b;
Packit 9c3e7e
Packit 9c3e7e
	a = (struct unicast_service_interval *) ain;
Packit 9c3e7e
	b = (struct unicast_service_interval *) bin;
Packit 9c3e7e
Packit 9c3e7e
	return timespec_compare(&a->tmo, &b->tmo);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void initialize_interval(struct unicast_service_interval *interval,
Packit 9c3e7e
				int log_period)
Packit 9c3e7e
{
Packit 9c3e7e
	LIST_INIT(&interval->clients);
Packit 9c3e7e
	interval->incr = log_to_timespec(log_period);
Packit 9c3e7e
	clock_gettime(CLOCK_MONOTONIC, &interval->tmo);
Packit 9c3e7e
	interval->tmo.tv_nsec += 10000000;
Packit 9c3e7e
	timespec_normalize(&interval->tmo);
Packit 9c3e7e
	interval->log_period = log_period;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void interval_increment(struct unicast_service_interval *i)
Packit 9c3e7e
{
Packit 9c3e7e
	i->tmo.tv_sec += i->incr.tv_sec;
Packit 9c3e7e
	i->tmo.tv_nsec += i->incr.tv_nsec;
Packit 9c3e7e
	timespec_normalize(&i->tmo);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static struct timespec log_to_timespec(int log_seconds)
Packit 9c3e7e
{
Packit 9c3e7e
	struct timespec ts = {0, 0};
Packit 9c3e7e
	uint64_t ns;
Packit 9c3e7e
	int i;
Packit 9c3e7e
Packit 9c3e7e
	if (log_seconds < 0) {
Packit 9c3e7e
		log_seconds *= -1;
Packit 9c3e7e
		for (i = 1, ns = 500000000ULL; i < log_seconds; i++) {
Packit 9c3e7e
			ns >>= 1;
Packit 9c3e7e
		}
Packit 9c3e7e
		ts.tv_nsec = ns;
Packit 9c3e7e
	} else {
Packit 9c3e7e
		ts.tv_sec = 1 << log_seconds;
Packit 9c3e7e
	}
Packit 9c3e7e
	return ts;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/*
Packit 9c3e7e
 * Returns:
Packit 9c3e7e
 *    1  if 'a' is before 'b'
Packit 9c3e7e
 *   -1  if 'a' is after  'b'
Packit 9c3e7e
 *    0  otherwise
Packit 9c3e7e
 */
Packit 9c3e7e
static int timespec_compare(struct timespec *a, struct timespec *b)
Packit 9c3e7e
{
Packit 9c3e7e
	if (a->tv_sec < b->tv_sec) {
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (b->tv_sec < a->tv_sec) {
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (a->tv_nsec < b->tv_nsec) {
Packit 9c3e7e
		return 1;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (b->tv_nsec < a->tv_nsec) {
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void timespec_normalize(struct timespec *ts)
Packit 9c3e7e
{
Packit 9c3e7e
	while (ts->tv_nsec >= NS_PER_SEC) {
Packit 9c3e7e
		ts->tv_nsec -= NS_PER_SEC;
Packit 9c3e7e
		ts->tv_sec++;
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int unicast_service_clients(struct port *p,
Packit 9c3e7e
				   struct unicast_service_interval *interval)
Packit 9c3e7e
{
Packit 9c3e7e
	struct unicast_client_address *client, *next;
Packit 9c3e7e
	struct timespec now;
Packit 9c3e7e
	int err = 0;
Packit 9c3e7e
Packit 9c3e7e
	err = clock_gettime(CLOCK_MONOTONIC, &now;;
Packit 9c3e7e
	if (err) {
Packit 9c3e7e
		pr_err("clock_gettime failed: %m");
Packit 9c3e7e
		return err;
Packit 9c3e7e
	}
Packit 9c3e7e
	LIST_FOREACH_SAFE(client, &interval->clients, list, next) {
Packit 9c3e7e
		pr_debug("%s wants 0x%x", pid2str(&client->portIdentity),
Packit 9c3e7e
			 client->message_types);
Packit 9c3e7e
		if (now.tv_sec > client->grant_tmo) {
Packit 9c3e7e
			pr_debug("%s service of 0x%x expired",
Packit 9c3e7e
				 pid2str(&client->portIdentity),
Packit 9c3e7e
				 client->message_types);
Packit 9c3e7e
			LIST_REMOVE(client, list);
Packit 9c3e7e
			free(client);
Packit 9c3e7e
			continue;
Packit 9c3e7e
		}
Packit 9c3e7e
		if (client->message_types & (1 << ANNOUNCE)) {
Packit 9c3e7e
			if (port_tx_announce(p, &client->addr)) {
Packit 9c3e7e
				err = -1;
Packit 9c3e7e
			}
Packit 9c3e7e
		}
Packit 9c3e7e
		if (client->message_types & (1 << SYNC)) {
Packit 9c3e7e
			if (port_tx_sync(p, &client->addr)) {
Packit 9c3e7e
				err = -1;
Packit 9c3e7e
			}
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
	return err;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void unicast_service_extend(struct unicast_client_address *client,
Packit 9c3e7e
				   struct request_unicast_xmit_tlv *req)
Packit 9c3e7e
{
Packit 9c3e7e
	struct timespec now;
Packit 9c3e7e
	time_t tmo;
Packit 9c3e7e
	int err;
Packit 9c3e7e
Packit 9c3e7e
	err = clock_gettime(CLOCK_MONOTONIC, &now;;
Packit 9c3e7e
	if (err) {
Packit 9c3e7e
		pr_err("clock_gettime failed: %m");
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
	tmo = now.tv_sec + req->durationField;
Packit 9c3e7e
	if (tmo > client->grant_tmo) {
Packit 9c3e7e
		client->grant_tmo = tmo;
Packit 9c3e7e
		pr_debug("%s grant of 0x%x extended to %ld",
Packit 9c3e7e
			 pid2str(&client->portIdentity),
Packit 9c3e7e
			 client->message_types, tmo);
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int unicast_service_rearm_timer(struct port *p)
Packit 9c3e7e
{
Packit 9c3e7e
	struct unicast_service_interval *interval;
Packit 9c3e7e
	struct itimerspec tmo;
Packit 9c3e7e
	int fd;
Packit 9c3e7e
Packit 9c3e7e
	fd = p->fda.fd[FD_UNICAST_SRV_TIMER];
Packit 9c3e7e
	memset(&tmo, 0, sizeof(tmo));
Packit 9c3e7e
	interval = pqueue_peek(p->unicast_service->queue);
Packit 9c3e7e
	if (interval) {
Packit 9c3e7e
		tmo.it_value = interval->tmo;
Packit 9c3e7e
		pr_debug("arming timer tmo={%ld,%ld}",
Packit 9c3e7e
			 interval->tmo.tv_sec, interval->tmo.tv_nsec);
Packit 9c3e7e
	} else {
Packit 9c3e7e
		pr_debug("stopping unicast service timer");
Packit 9c3e7e
	}
Packit 9c3e7e
	return timerfd_settime(fd, TFD_TIMER_ABSTIME, &tmo, NULL);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static int unicast_service_reply(struct port *p, struct ptp_message *dst,
Packit 9c3e7e
				 struct request_unicast_xmit_tlv *req,
Packit 9c3e7e
				 int duration)
Packit 9c3e7e
{
Packit 9c3e7e
	struct ptp_message *msg;
Packit 9c3e7e
	int err;
Packit 9c3e7e
Packit 9c3e7e
	msg = port_signaling_construct(p, &dst->address,
Packit 9c3e7e
				       &dst->header.sourcePortIdentity);
Packit 9c3e7e
	if (!msg) {
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	err = attach_grant(msg, req, duration);
Packit 9c3e7e
	if (err) {
Packit 9c3e7e
		goto out;
Packit 9c3e7e
	}
Packit 9c3e7e
	err = port_prepare_and_send(p, msg, TRANS_GENERAL);
Packit 9c3e7e
	if (err) {
Packit 9c3e7e
		pr_err("port %hu: signaling message failed", portnum(p));
Packit 9c3e7e
	}
Packit 9c3e7e
out:
Packit 9c3e7e
	msg_put(msg);
Packit 9c3e7e
	return err;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/* public methods */
Packit 9c3e7e
Packit 9c3e7e
int unicast_service_add(struct port *p, struct ptp_message *m,
Packit 9c3e7e
			struct tlv_extra *extra)
Packit 9c3e7e
{
Packit 9c3e7e
	struct unicast_client_address *client = NULL, *ctmp, *next;
Packit 9c3e7e
	struct unicast_service_interval *interval = NULL, *itmp;
Packit 9c3e7e
	struct request_unicast_xmit_tlv *req;
Packit 9c3e7e
	unsigned int mask;
Packit 9c3e7e
	uint8_t mtype;
Packit 9c3e7e
Packit 9c3e7e
	if (!p->unicast_service) {
Packit 9c3e7e
		return SERVICE_DISABLED;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	req = (struct request_unicast_xmit_tlv *) extra->tlv;
Packit 9c3e7e
	mtype = req->message_type >> 4;
Packit 9c3e7e
	mask = 1 << mtype;
Packit 9c3e7e
Packit 9c3e7e
	switch (mtype) {
Packit 9c3e7e
	case ANNOUNCE:
Packit 9c3e7e
	case SYNC:
Packit 9c3e7e
		break;
Packit 9c3e7e
	case DELAY_RESP:
Packit 9c3e7e
	case PDELAY_RESP:
Packit 9c3e7e
		return SERVICE_GRANTED;
Packit 9c3e7e
	default:
Packit 9c3e7e
		return SERVICE_DENIED;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit babef3
	if (req->logInterMessagePeriod < MIN_LOG_INTER_MESSAGE_PERIOD ||
Packit babef3
	    req->logInterMessagePeriod > MAX_LOG_INTER_MESSAGE_PERIOD) {
Packit babef3
		return SERVICE_DENIED;
Packit babef3
	}
Packit babef3
Packit babef3
	if (req->durationField > MAX_DURATION) {
Packit babef3
		req->durationField = MAX_DURATION;
Packit babef3
	}
Packit babef3
Packit 9c3e7e
	LIST_FOREACH(itmp, &p->unicast_service->intervals, list) {
Packit 9c3e7e
		/*
Packit 9c3e7e
		 * Remember the interval of interest.
Packit 9c3e7e
		 */
Packit 9c3e7e
		if (itmp->log_period == req->logInterMessagePeriod) {
Packit 9c3e7e
			interval = itmp;
Packit 9c3e7e
		}
Packit 9c3e7e
		/*
Packit 9c3e7e
		 * Find any client records, and remove any stale contract.
Packit 9c3e7e
		 */
Packit 9c3e7e
		LIST_FOREACH_SAFE(ctmp, &itmp->clients, list, next) {
Packit 9c3e7e
			if (!addreq(transport_type(p->trp),
Packit 9c3e7e
				    &ctmp->addr, &m->address)) {
Packit 9c3e7e
				continue;
Packit 9c3e7e
			}
Packit 9c3e7e
			if (interval == itmp) {
Packit 9c3e7e
				if (ctmp->message_types & mask) {
Packit 9c3e7e
					/* Contract is unchanged. */
Packit 9c3e7e
					unicast_service_extend(ctmp, req);
Packit 9c3e7e
					return SERVICE_GRANTED;
Packit 9c3e7e
				}
Packit 9c3e7e
				/* This is the one to use. */
Packit 9c3e7e
				client = ctmp;
Packit 9c3e7e
				continue;
Packit 9c3e7e
			}
Packit 9c3e7e
			/* Clear any stale contracts. */
Packit 9c3e7e
			ctmp->message_types &= ~mask;
Packit 9c3e7e
			if (!ctmp->message_types) {
Packit 9c3e7e
				LIST_REMOVE(ctmp, list);
Packit 9c3e7e
				free(ctmp);
Packit 9c3e7e
			}
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (client) {
Packit 9c3e7e
		client->message_types |= mask;
Packit 9c3e7e
		unicast_service_extend(client, req);
Packit 9c3e7e
		return SERVICE_GRANTED;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	client = calloc(1, sizeof(*client));
Packit 9c3e7e
	if (!client) {
Packit 9c3e7e
		return SERVICE_DENIED;
Packit 9c3e7e
	}
Packit 9c3e7e
	client->portIdentity = m->header.sourcePortIdentity;
Packit 9c3e7e
	client->message_types = mask;
Packit 9c3e7e
	client->addr = m->address;
Packit 9c3e7e
	unicast_service_extend(client, req);
Packit 9c3e7e
Packit 9c3e7e
	if (!interval) {
Packit 9c3e7e
		interval = calloc(1, sizeof(*interval));
Packit 9c3e7e
		if (!interval) {
Packit 9c3e7e
			free(client);
Packit 9c3e7e
			return SERVICE_DENIED;
Packit 9c3e7e
		}
Packit 9c3e7e
		initialize_interval(interval, req->logInterMessagePeriod);
Packit 9c3e7e
		LIST_INSERT_HEAD(&p->unicast_service->intervals, interval, list);
Packit 9c3e7e
		if (pqueue_insert(p->unicast_service->queue, interval)) {
Packit 9c3e7e
			LIST_REMOVE(interval, list);
Packit 9c3e7e
			free(interval);
Packit 9c3e7e
			free(client);
Packit 9c3e7e
			return SERVICE_DENIED;
Packit 9c3e7e
		}
Packit 9c3e7e
		unicast_service_rearm_timer(p);
Packit 9c3e7e
	}
Packit 9c3e7e
	LIST_INSERT_HEAD(&interval->clients, client, list);
Packit 9c3e7e
	return SERVICE_GRANTED;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void unicast_service_cleanup(struct port *p)
Packit 9c3e7e
{
Packit 9c3e7e
	struct unicast_service_interval *itmp, *inext;
Packit 9c3e7e
	struct unicast_client_address *ctmp, *cnext;
Packit 9c3e7e
Packit 9c3e7e
	if (!p->unicast_service) {
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
	LIST_FOREACH_SAFE(itmp, &p->unicast_service->intervals, list, inext) {
Packit 9c3e7e
		LIST_FOREACH_SAFE(ctmp, &itmp->clients, list, cnext) {
Packit 9c3e7e
			LIST_REMOVE(ctmp, list);
Packit 9c3e7e
			free(ctmp);
Packit 9c3e7e
		}
Packit 9c3e7e
		LIST_REMOVE(itmp, list);
Packit 9c3e7e
		free(itmp);
Packit 9c3e7e
	}
Packit 9c3e7e
	pqueue_destroy(p->unicast_service->queue);
Packit 9c3e7e
	free(p->unicast_service);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int unicast_service_deny(struct port *p, struct ptp_message *m,
Packit 9c3e7e
			 struct tlv_extra *extra)
Packit 9c3e7e
{
Packit 9c3e7e
	struct request_unicast_xmit_tlv *req =
Packit 9c3e7e
		(struct request_unicast_xmit_tlv *) extra->tlv;
Packit 9c3e7e
Packit 9c3e7e
	return unicast_service_reply(p, m, req, 0);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int unicast_service_grant(struct port *p, struct ptp_message *m,
Packit 9c3e7e
			  struct tlv_extra *extra)
Packit 9c3e7e
{
Packit 9c3e7e
	struct request_unicast_xmit_tlv *req =
Packit 9c3e7e
		(struct request_unicast_xmit_tlv *) extra->tlv;
Packit 9c3e7e
Packit 9c3e7e
	return unicast_service_reply(p, m, req, req->durationField);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int unicast_service_initialize(struct port *p)
Packit 9c3e7e
{
Packit 9c3e7e
	struct config *cfg = clock_config(p->clock);
Packit 9c3e7e
Packit 9c3e7e
	if (!config_get_int(cfg, p->name, "unicast_listen")) {
Packit 9c3e7e
		return 0;
Packit 9c3e7e
	}
Packit 9c3e7e
	if (config_set_section_int(cfg, p->name, "hybrid_e2e", 1)) {
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	p->unicast_service = calloc(1, sizeof(*p->unicast_service));
Packit 9c3e7e
	if (!p->unicast_service) {
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	LIST_INIT(&p->unicast_service->intervals);
Packit 9c3e7e
Packit 9c3e7e
	p->unicast_service->queue = pqueue_create(QUEUE_LEN, compare_timeout);
Packit 9c3e7e
	if (!p->unicast_service->queue) {
Packit 9c3e7e
		free(p->unicast_service);
Packit 9c3e7e
		return -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	p->inhibit_multicast_service =
Packit 9c3e7e
		config_get_int(cfg, p->name, "inhibit_multicast_service");
Packit 9c3e7e
Packit 9c3e7e
	return 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
void unicast_service_remove(struct port *p, struct ptp_message *m,
Packit 9c3e7e
			    struct tlv_extra *extra)
Packit 9c3e7e
{
Packit 9c3e7e
	struct unicast_client_address *ctmp, *next;
Packit 9c3e7e
	struct cancel_unicast_xmit_tlv *cancel;
Packit 9c3e7e
	struct unicast_service_interval *itmp;
Packit 9c3e7e
	unsigned int mask;
Packit 9c3e7e
	uint8_t mtype;
Packit 9c3e7e
Packit 9c3e7e
	if (!p->unicast_service) {
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
	cancel = (struct cancel_unicast_xmit_tlv *) extra->tlv;
Packit 9c3e7e
	if (cancel->message_type_flags & CANCEL_UNICAST_MAINTAIN_REQUEST) {
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
	mtype = cancel->message_type_flags >> 4;
Packit 9c3e7e
	mask = 1 << mtype;
Packit 9c3e7e
Packit 9c3e7e
	switch (mtype) {
Packit 9c3e7e
	case ANNOUNCE:
Packit 9c3e7e
	case SYNC:
Packit 9c3e7e
		break;
Packit 9c3e7e
	case DELAY_RESP:
Packit 9c3e7e
	case PDELAY_RESP:
Packit 9c3e7e
	default:
Packit 9c3e7e
		return;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	LIST_FOREACH(itmp, &p->unicast_service->intervals, list) {
Packit 9c3e7e
		LIST_FOREACH_SAFE(ctmp, &itmp->clients, list, next) {
Packit 9c3e7e
			if (!addreq(transport_type(p->trp),
Packit 9c3e7e
				    &ctmp->addr, &m->address)) {
Packit 9c3e7e
				continue;
Packit 9c3e7e
			}
Packit 9c3e7e
			if (ctmp->message_types & mask) {
Packit 9c3e7e
				ctmp->message_types &= ~mask;
Packit 9c3e7e
				if (!ctmp->message_types) {
Packit 9c3e7e
					LIST_REMOVE(ctmp, list);
Packit 9c3e7e
					free(ctmp);
Packit 9c3e7e
				}
Packit 9c3e7e
				return;
Packit 9c3e7e
			}
Packit 9c3e7e
		}
Packit 9c3e7e
	}
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
int unicast_service_timer(struct port *p)
Packit 9c3e7e
{
Packit 9c3e7e
	struct unicast_service_interval *interval;
Packit 9c3e7e
	int err = 0, master = 0;
Packit 9c3e7e
	struct timespec now;
Packit 9c3e7e
Packit 9c3e7e
	if (!p->unicast_service) {
Packit 9c3e7e
		return 0;
Packit 9c3e7e
	}
Packit 9c3e7e
	clock_gettime(CLOCK_MONOTONIC, &now;;
Packit 9c3e7e
Packit 9c3e7e
	switch (p->state) {
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
	case PS_UNCALIBRATED:
Packit 9c3e7e
	case PS_SLAVE:
Packit 9c3e7e
		break;
Packit 9c3e7e
	case PS_MASTER:
Packit 9c3e7e
	case PS_GRAND_MASTER:
Packit 9c3e7e
		master = 1;
Packit 9c3e7e
		break;
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	while ((interval = pqueue_peek(p->unicast_service->queue)) != NULL) {
Packit 9c3e7e
Packit 9c3e7e
		pr_debug("peek i={2^%d} tmo={%ld,%ld}", interval->log_period,
Packit 9c3e7e
			 interval->tmo.tv_sec, interval->tmo.tv_nsec);
Packit 9c3e7e
Packit e5c6ac
		if (timespec_compare(&now, &interval->tmo) > 0) {
Packit 9c3e7e
			break;
Packit 9c3e7e
		}
Packit 9c3e7e
		interval = pqueue_extract(p->unicast_service->queue);
Packit 9c3e7e
Packit 9c3e7e
		if (master && unicast_service_clients(p, interval)) {
Packit 9c3e7e
			err = -1;
Packit 9c3e7e
		}
Packit 9c3e7e
Packit 9c3e7e
		if (LIST_EMPTY(&interval->clients)) {
Packit 9c3e7e
			pr_debug("retire interval 2^%d", interval->log_period);
Packit 9c3e7e
			LIST_REMOVE(interval, list);
Packit 9c3e7e
			free(interval);
Packit 9c3e7e
			continue;
Packit 9c3e7e
		}
Packit 9c3e7e
Packit 9c3e7e
		interval_increment(interval);
Packit 9c3e7e
		pr_debug("next i={2^%d} tmo={%ld,%ld}", interval->log_period,
Packit 9c3e7e
			 interval->tmo.tv_sec, interval->tmo.tv_nsec);
Packit 9c3e7e
		pqueue_insert(p->unicast_service->queue, interval);
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	if (unicast_service_rearm_timer(p)) {
Packit 9c3e7e
		err = -1;
Packit 9c3e7e
	}
Packit 9c3e7e
	return err;
Packit 9c3e7e
}