Blame msg.h

Packit 9c3e7e
/**
Packit 9c3e7e
 * @file msg.h
Packit 9c3e7e
 * @brief Implements the various PTP message types.
Packit 9c3e7e
 * @note Copyright (C) 2011 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
#ifndef HAVE_MSG_H
Packit 9c3e7e
#define HAVE_MSG_H
Packit 9c3e7e
Packit 9c3e7e
#include <stdio.h>
Packit 9c3e7e
#include <sys/queue.h>
Packit 9c3e7e
#include <time.h>
Packit 9c3e7e
#include <asm/byteorder.h>
Packit 9c3e7e
Packit 9c3e7e
#include "address.h"
Packit 9c3e7e
#include "ddt.h"
Packit 9c3e7e
#include "tlv.h"
Packit 9c3e7e
#include "tmv.h"
Packit 9c3e7e
Packit 9c3e7e
#define PTP_VERSION 2
Packit 9c3e7e
Packit 9c3e7e
/* Values for the messageType field */
Packit 9c3e7e
#define SYNC                  0x0
Packit 9c3e7e
#define DELAY_REQ             0x1
Packit 9c3e7e
#define PDELAY_REQ            0x2
Packit 9c3e7e
#define PDELAY_RESP           0x3
Packit 9c3e7e
#define FOLLOW_UP             0x8
Packit 9c3e7e
#define DELAY_RESP            0x9
Packit 9c3e7e
#define PDELAY_RESP_FOLLOW_UP 0xA
Packit 9c3e7e
#define ANNOUNCE              0xB
Packit 9c3e7e
#define SIGNALING             0xC
Packit 9c3e7e
#define MANAGEMENT            0xD
Packit 9c3e7e
Packit 9c3e7e
/* Bits for flagField[0] */
Packit 9c3e7e
#define ALT_MASTER     (1<<0)
Packit 9c3e7e
#define TWO_STEP       (1<<1)
Packit 9c3e7e
#define UNICAST        (1<<2)
Packit 9c3e7e
Packit 9c3e7e
/* Bits for flagField[1] */
Packit 9c3e7e
#define LEAP_61        (1<<0)
Packit 9c3e7e
#define LEAP_59        (1<<1)
Packit 9c3e7e
#define UTC_OFF_VALID  (1<<2)
Packit 9c3e7e
#define PTP_TIMESCALE  (1<<3)
Packit 9c3e7e
#define TIME_TRACEABLE (1<<4)
Packit 9c3e7e
#define FREQ_TRACEABLE (1<<5)
Packit 9c3e7e
Packit 9c3e7e
enum timestamp_type {
Packit 9c3e7e
	TS_SOFTWARE,
Packit 9c3e7e
	TS_HARDWARE,
Packit 9c3e7e
	TS_LEGACY_HW,
Packit 9c3e7e
	TS_ONESTEP,
Packit 9c3e7e
	TS_P2P1STEP,
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
struct hw_timestamp {
Packit 9c3e7e
	enum timestamp_type type;
Packit 9c3e7e
	tmv_t ts;
Packit 9c3e7e
	tmv_t sw;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
enum controlField {
Packit 9c3e7e
	CTL_SYNC,
Packit 9c3e7e
	CTL_DELAY_REQ,
Packit 9c3e7e
	CTL_FOLLOW_UP,
Packit 9c3e7e
	CTL_DELAY_RESP,
Packit 9c3e7e
	CTL_MANAGEMENT,
Packit 9c3e7e
	CTL_OTHER,
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
struct ptp_header {
Packit 9c3e7e
	uint8_t             tsmt; /* transportSpecific | messageType */
Packit 9c3e7e
	uint8_t             ver;  /* reserved          | versionPTP  */
Packit 9c3e7e
	UInteger16          messageLength;
Packit 9c3e7e
	UInteger8           domainNumber;
Packit 9c3e7e
	Octet               reserved1;
Packit 9c3e7e
	Octet               flagField[2];
Packit 9c3e7e
	Integer64           correction;
Packit 9c3e7e
	UInteger32          reserved2;
Packit 9c3e7e
	struct PortIdentity sourcePortIdentity;
Packit 9c3e7e
	UInteger16          sequenceId;
Packit 9c3e7e
	UInteger8           control;
Packit 9c3e7e
	Integer8            logMessageInterval;
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct announce_msg {
Packit 9c3e7e
	struct ptp_header    hdr;
Packit 9c3e7e
	struct Timestamp     originTimestamp;
Packit 9c3e7e
	Integer16            currentUtcOffset;
Packit 9c3e7e
	Octet                reserved;
Packit 9c3e7e
	UInteger8            grandmasterPriority1;
Packit 9c3e7e
	struct ClockQuality  grandmasterClockQuality;
Packit 9c3e7e
	UInteger8            grandmasterPriority2;
Packit 9c3e7e
	struct ClockIdentity grandmasterIdentity;
Packit 9c3e7e
	UInteger16           stepsRemoved;
Packit 9c3e7e
	Enumeration8         timeSource;
Packit 9c3e7e
	uint8_t              suffix[0];
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct sync_msg {
Packit 9c3e7e
	struct ptp_header   hdr;
Packit 9c3e7e
	struct Timestamp    originTimestamp;
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct delay_req_msg {
Packit 9c3e7e
	struct ptp_header   hdr;
Packit 9c3e7e
	struct Timestamp    originTimestamp;
Packit 9c3e7e
	uint8_t             suffix[0];
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct follow_up_msg {
Packit 9c3e7e
	struct ptp_header   hdr;
Packit 9c3e7e
	struct Timestamp    preciseOriginTimestamp;
Packit 9c3e7e
	uint8_t             suffix[0];
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct delay_resp_msg {
Packit 9c3e7e
	struct ptp_header   hdr;
Packit 9c3e7e
	struct Timestamp    receiveTimestamp;
Packit 9c3e7e
	struct PortIdentity requestingPortIdentity;
Packit 9c3e7e
	uint8_t             suffix[0];
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct pdelay_req_msg {
Packit 9c3e7e
	struct ptp_header   hdr;
Packit 9c3e7e
	struct Timestamp    originTimestamp;
Packit 9c3e7e
	struct PortIdentity reserved;
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct pdelay_resp_msg {
Packit 9c3e7e
	struct ptp_header   hdr;
Packit 9c3e7e
	struct Timestamp    requestReceiptTimestamp;
Packit 9c3e7e
	struct PortIdentity requestingPortIdentity;
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct pdelay_resp_fup_msg {
Packit 9c3e7e
	struct ptp_header   hdr;
Packit 9c3e7e
	struct Timestamp    responseOriginTimestamp;
Packit 9c3e7e
	struct PortIdentity requestingPortIdentity;
Packit 9c3e7e
	uint8_t             suffix[0];
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct signaling_msg {
Packit 9c3e7e
	struct ptp_header   hdr;
Packit 9c3e7e
	struct PortIdentity targetPortIdentity;
Packit 9c3e7e
	uint8_t             suffix[0];
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct management_msg {
Packit 9c3e7e
	struct ptp_header   hdr;
Packit 9c3e7e
	struct PortIdentity targetPortIdentity;
Packit 9c3e7e
	UInteger8           startingBoundaryHops;
Packit 9c3e7e
	UInteger8           boundaryHops;
Packit 9c3e7e
	uint8_t             flags; /* reserved | actionField */
Packit 9c3e7e
	uint8_t             reserved;
Packit 9c3e7e
	uint8_t             suffix[0];
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct message_data {
Packit 9c3e7e
	uint8_t buffer[1500];
Packit 9c3e7e
} PACKED;
Packit 9c3e7e
Packit 9c3e7e
struct ptp_message {
Packit 9c3e7e
	union {
Packit 9c3e7e
		struct ptp_header          header;
Packit 9c3e7e
		struct announce_msg        announce;
Packit 9c3e7e
		struct sync_msg            sync;
Packit 9c3e7e
		struct delay_req_msg       delay_req;
Packit 9c3e7e
		struct follow_up_msg       follow_up;
Packit 9c3e7e
		struct delay_resp_msg      delay_resp;
Packit 9c3e7e
		struct pdelay_req_msg      pdelay_req;
Packit 9c3e7e
		struct pdelay_resp_msg     pdelay_resp;
Packit 9c3e7e
		struct pdelay_resp_fup_msg pdelay_resp_fup;
Packit 9c3e7e
		struct signaling_msg       signaling;
Packit 9c3e7e
		struct management_msg      management;
Packit 9c3e7e
		struct message_data        data;
Packit 9c3e7e
	} PACKED;
Packit 9c3e7e
	/**/
Packit 9c3e7e
	int tail_room;
Packit 9c3e7e
	int refcnt;
Packit 9c3e7e
	TAILQ_ENTRY(ptp_message) list;
Packit 9c3e7e
	struct {
Packit 9c3e7e
		/**
Packit 9c3e7e
		 * Contains the time stamp from the packet data in a
Packit 9c3e7e
		 * native binary format for the host machine. The
Packit 9c3e7e
		 * exact source of the time stamp's value depends on
Packit 9c3e7e
		 * the message type:
Packit 9c3e7e
		 *
Packit 9c3e7e
		 * - announce    originTimestamp
Packit 9c3e7e
		 * - follow_up   preciseOriginTimestamp
Packit 9c3e7e
		 * - sync        originTimestamp
Packit 9c3e7e
		 * - delay_req   originTimestamp
Packit 9c3e7e
		 * - pdelay_resp     requestReceiptTimestamp
Packit 9c3e7e
		 * - pdelay_resp_fup responseOriginTimestamp
Packit 9c3e7e
		 */
Packit 9c3e7e
		struct timestamp pdu;
Packit 9c3e7e
		/**
Packit 9c3e7e
		 * Approximate ingress time stamp using the relative
Packit 9c3e7e
		 * CLOCK_MONOTONIC. Used to determine when announce
Packit 9c3e7e
		 * messages have expired.
Packit 9c3e7e
		 */
Packit 9c3e7e
		struct timespec host;
Packit 9c3e7e
	} ts;
Packit 9c3e7e
	/**
Packit 9c3e7e
	 * Contains the ingress time stamp obtained by the
Packit 9c3e7e
	 * SO_TIMESTAMPING socket option.
Packit 9c3e7e
	 */
Packit 9c3e7e
	struct hw_timestamp hwts;
Packit 9c3e7e
	/**
Packit 9c3e7e
	 * Contains the address this message was received from or should be
Packit 9c3e7e
	 * sent to.
Packit 9c3e7e
	 */
Packit 9c3e7e
	struct address address;
Packit 9c3e7e
	/**
Packit 9c3e7e
	 * List of TLV descriptors.  Each item in the list contains
Packit 9c3e7e
	 * pointers to the appended TLVs.
Packit 9c3e7e
	 */
Packit 9c3e7e
	TAILQ_HEAD(tlv_list, tlv_extra) tlv_list;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Obtain the action field from a management message.
Packit 9c3e7e
 * @param m  A management message.
Packit 9c3e7e
 * @return   The value of the action field.
Packit 9c3e7e
 */
Packit 9c3e7e
static inline uint8_t management_action(struct ptp_message *m)
Packit 9c3e7e
{
Packit 9c3e7e
	return m->management.flags & 0x0f;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Test a given bit in a message's flag field.
Packit 9c3e7e
 * @param m      Message to test.
Packit 9c3e7e
 * @param index  Index into flag field, either 0 or 1.
Packit 9c3e7e
 * @param bit    Bit mask of one bit to test.
Packit 9c3e7e
 * @return       One if bit is set, zero otherwise.
Packit 9c3e7e
 */
Packit 9c3e7e
static inline Boolean field_is_set(struct ptp_message *m, int index, Octet bit)
Packit 9c3e7e
{
Packit 9c3e7e
	return m->header.flagField[index] & bit ? TRUE : FALSE;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Append a new TLV onto a message for transmission.
Packit 9c3e7e
 *
Packit 9c3e7e
 * This is a high level API designed for the transmit path.  The
Packit 9c3e7e
 * function allocates a new descriptor, initializes its .tlv field,
Packit 9c3e7e
 * and ensures that the TLV will fit into the message buffer.  This
Packit 9c3e7e
 * function increments the message length field by 'length' before
Packit 9c3e7e
 * returning.
Packit 9c3e7e
 *
Packit 9c3e7e
 * @param msg     A message obtained using msg_allocate().  At a mininum,
Packit 9c3e7e
 *                the message type and length fields must set by the caller.
Packit 9c3e7e
 * @param length  The length of the TLV to append.
Packit 9c3e7e
 * @return        A pointer to a TLV descriptor on success or NULL otherwise.
Packit 9c3e7e
 */
Packit 9c3e7e
struct tlv_extra *msg_tlv_append(struct ptp_message *msg, int length);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Place a TLV descriptor into a message's list of TLVs.
Packit 9c3e7e
 *
Packit 9c3e7e
 * @param msg     A message obtained using msg_allocate().
Packit 9c3e7e
 * @param extra   The TLV to be added to the list.
Packit 9c3e7e
 */
Packit 9c3e7e
void msg_tlv_attach(struct ptp_message *msg, struct tlv_extra *extra);
Packit 9c3e7e
Packit 9c3e7e
/*
Packit 9c3e7e
 * Return the number of TLVs attached to a message.
Packit 9c3e7e
 * @param msg  A message obtained using @ref msg_allocate().
Packit 9c3e7e
 * @return     The number of attached TLVs.
Packit 9c3e7e
 */
Packit 9c3e7e
int msg_tlv_count(struct ptp_message *msg);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Obtain the transportSpecific field from a message.
Packit 9c3e7e
 * @param m  Message to test.
Packit 9c3e7e
 * @return   The value of the transportSpecific field. Note that the
Packit 9c3e7e
 *           value is returned unshifted, in the upper nibble.
Packit 9c3e7e
 */
Packit 9c3e7e
static inline UInteger8 msg_transport_specific(struct ptp_message *m)
Packit 9c3e7e
{
Packit 9c3e7e
	return m->header.tsmt & 0xf0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Obtain the message type.
Packit 9c3e7e
 * @param m  Message to test.
Packit 9c3e7e
 * @return   The value of the messageType field.
Packit 9c3e7e
 */
Packit 9c3e7e
static inline int msg_type(struct ptp_message *m)
Packit 9c3e7e
{
Packit 9c3e7e
	return m->header.tsmt & 0x0f;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Allocate a new message instance.
Packit 9c3e7e
 *
Packit 9c3e7e
 * Messages are reference counted, and newly allocated messages have a
Packit 9c3e7e
 * reference count of one. Allocated messages are freed using the
Packit 9c3e7e
 * function @ref msg_put().
Packit 9c3e7e
 *
Packit 9c3e7e
 * @return Pointer to a message on success, NULL otherwise.
Packit 9c3e7e
 */
Packit 9c3e7e
struct ptp_message *msg_allocate(void);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Release all of the memory in the message cache.
Packit 9c3e7e
 */
Packit 9c3e7e
void msg_cleanup(void);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Duplicate a message instance.
Packit 9c3e7e
 *
Packit 9c3e7e
 * This function accepts a message in network byte order and returns a
Packit 9c3e7e
 * duplicate in host byte.
Packit 9c3e7e
 *
Packit 9c3e7e
 * Messages are reference counted, and newly allocated messages have a
Packit 9c3e7e
 * reference count of one. Allocated messages are freed using the
Packit 9c3e7e
 * function @ref msg_put().
Packit 9c3e7e
 *
Packit 9c3e7e
 * @param msg  A message obtained using @ref msg_allocate().
Packit 9c3e7e
 *             The passed message must be in network byte order, not
Packit 9c3e7e
 *             having been passed to @ref msg_post_recv().
Packit 9c3e7e
 *
Packit 9c3e7e
 * @return     Pointer to a message on success, NULL otherwise.
Packit 9c3e7e
 *             The returned message will be in host byte order, having
Packit 9c3e7e
 *             been passed to @ref msg_post_recv().
Packit 9c3e7e
 */
Packit 9c3e7e
struct ptp_message *msg_duplicate(struct ptp_message *msg, int cnt);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Obtain a reference to a message, increasing its reference count by one.
Packit 9c3e7e
 * @param m A message obtained using @ref msg_allocate().
Packit 9c3e7e
 */
Packit 9c3e7e
void msg_get(struct ptp_message *m);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Process messages after reception.
Packit 9c3e7e
 * @param m    A message obtained using @ref msg_allocate().
Packit 9c3e7e
 * @param cnt  The size of 'm' in bytes.
Packit 9c3e7e
 * @return   Zero on success, non-zero if the message is invalid.
Packit 9c3e7e
 */
Packit 9c3e7e
int msg_post_recv(struct ptp_message *m, int cnt);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Prepare messages for transmission.
Packit 9c3e7e
 * @param m  A message obtained using @ref msg_allocate().
Packit 9c3e7e
 * @return   Zero on success, non-zero if the message is invalid.
Packit 9c3e7e
 */
Packit 9c3e7e
int msg_pre_send(struct ptp_message *m);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Print messages for debugging purposes.
Packit 9c3e7e
 * @param type  Value of the messageType field as returned by @ref msg_type().
Packit 9c3e7e
 * @return      String describing the message type.
Packit 9c3e7e
 */
Packit 9c3e7e
const char *msg_type_string(int type);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Print messages for debugging purposes.
Packit 9c3e7e
 * @param m   A message obtained using @ref msg_allocate().
Packit 9c3e7e
 * @param fp  An open file pointer.
Packit 9c3e7e
 */
Packit 9c3e7e
void msg_print(struct ptp_message *m, FILE *fp);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Release a reference to a message, decreasing its reference count by one.
Packit 9c3e7e
 * @param m A message obtained using @ref msg_allocate().
Packit 9c3e7e
 */
Packit 9c3e7e
void msg_put(struct ptp_message *m);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Test whether an event message received a valid SO_TIMESTAMPING time stamp.
Packit 9c3e7e
 * @param m  Message to test.
Packit 9c3e7e
 * @return   One if the message is an event without a time stamp, zero otherwise.
Packit 9c3e7e
 */
Packit 9c3e7e
int msg_sots_missing(struct ptp_message *m);
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Test whether a message has a valid SO_TIMESTAMPING time stamp.
Packit 9c3e7e
 * @param m  Message to test.
Packit 9c3e7e
 * @return   One if the message has a valid time stamp, zero otherwise.
Packit 9c3e7e
 */
Packit 9c3e7e
static inline int msg_sots_valid(struct ptp_message *m)
Packit 9c3e7e
{
Packit 9c3e7e
	return !tmv_is_zero(m->hwts.ts);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Test whether a message is a unicast message.
Packit 9c3e7e
 * @param m  Message to test.
Packit 9c3e7e
 * @return   One if the message is unicast, zero otherwise.
Packit 9c3e7e
 */
Packit 9c3e7e
static inline Boolean msg_unicast(struct ptp_message *m)
Packit 9c3e7e
{
Packit 9c3e7e
	return field_is_set(m, 0, UNICAST);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Work around buggy 802.1AS switches.
Packit 9c3e7e
 */
Packit 9c3e7e
extern int assume_two_step;
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Test whether a message is one-step message.
Packit 9c3e7e
 * @param m  Message to test.
Packit 9c3e7e
 * @return   One if the message is a one-step, zero otherwise.
Packit 9c3e7e
 */
Packit 9c3e7e
static inline Boolean one_step(struct ptp_message *m)
Packit 9c3e7e
{
Packit 9c3e7e
	if (assume_two_step)
Packit 9c3e7e
		return 0;
Packit 9c3e7e
	return !field_is_set(m, 0, TWO_STEP);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Convert a 64 bit word into network byte order.
Packit 9c3e7e
 */
Packit 9c3e7e
static inline int64_t host2net64(int64_t val)
Packit 9c3e7e
{
Packit 9c3e7e
	return __cpu_to_be64(val);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
/**
Packit 9c3e7e
 * Convert a 64 bit word into host byte order.
Packit 9c3e7e
 */
Packit 9c3e7e
static inline int64_t net2host64(int64_t val)
Packit 9c3e7e
{
Packit 9c3e7e
	return __be64_to_cpu(val);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
#endif