2011-11-06 16:02:57 +08:00
|
|
|
/**
|
|
|
|
* @file msg.h
|
|
|
|
* @brief Implements the various PTP message types.
|
|
|
|
* @note Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
#ifndef HAVE_MSG_H
|
|
|
|
#define HAVE_MSG_H
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/queue.h>
|
|
|
|
#include <time.h>
|
2018-07-10 17:55:44 +08:00
|
|
|
#include <asm/byteorder.h>
|
2011-11-06 16:02:57 +08:00
|
|
|
|
2014-04-22 22:00:59 +08:00
|
|
|
#include "address.h"
|
2011-11-06 16:02:57 +08:00
|
|
|
#include "ddt.h"
|
2013-02-25 07:56:35 +08:00
|
|
|
#include "tlv.h"
|
2018-03-12 20:36:31 +08:00
|
|
|
#include "tmv.h"
|
2011-11-06 16:02:57 +08:00
|
|
|
|
2012-08-05 20:04:12 +08:00
|
|
|
#define PTP_VERSION 2
|
|
|
|
|
2011-11-06 16:02:57 +08:00
|
|
|
/* Values for the messageType field */
|
|
|
|
#define SYNC 0x0
|
|
|
|
#define DELAY_REQ 0x1
|
|
|
|
#define PDELAY_REQ 0x2
|
|
|
|
#define PDELAY_RESP 0x3
|
|
|
|
#define FOLLOW_UP 0x8
|
|
|
|
#define DELAY_RESP 0x9
|
|
|
|
#define PDELAY_RESP_FOLLOW_UP 0xA
|
|
|
|
#define ANNOUNCE 0xB
|
|
|
|
#define SIGNALING 0xC
|
|
|
|
#define MANAGEMENT 0xD
|
|
|
|
|
|
|
|
/* Bits for flagField[0] */
|
|
|
|
#define ALT_MASTER (1<<0)
|
|
|
|
#define TWO_STEP (1<<1)
|
|
|
|
#define UNICAST (1<<2)
|
|
|
|
|
|
|
|
/* Bits for flagField[1] */
|
|
|
|
#define LEAP_61 (1<<0)
|
|
|
|
#define LEAP_59 (1<<1)
|
|
|
|
#define UTC_OFF_VALID (1<<2)
|
|
|
|
#define PTP_TIMESCALE (1<<3)
|
|
|
|
#define TIME_TRACEABLE (1<<4)
|
|
|
|
#define FREQ_TRACEABLE (1<<5)
|
|
|
|
|
2019-03-29 11:32:28 +08:00
|
|
|
/*
|
|
|
|
* Signaling interval special values. For more info look at 802.1AS table 10-11
|
|
|
|
*/
|
|
|
|
#define SIGNAL_NO_CHANGE -128
|
|
|
|
#define SIGNAL_SET_INITIAL 126
|
|
|
|
|
2014-04-11 18:25:53 +08:00
|
|
|
enum timestamp_type {
|
|
|
|
TS_SOFTWARE,
|
|
|
|
TS_HARDWARE,
|
|
|
|
TS_LEGACY_HW,
|
|
|
|
TS_ONESTEP,
|
2018-02-16 01:16:15 +08:00
|
|
|
TS_P2P1STEP,
|
2014-04-11 18:25:53 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct hw_timestamp {
|
|
|
|
enum timestamp_type type;
|
2018-03-12 20:36:30 +08:00
|
|
|
tmv_t ts;
|
2018-03-12 20:36:31 +08:00
|
|
|
tmv_t sw;
|
2014-04-11 18:25:53 +08:00
|
|
|
};
|
|
|
|
|
2011-11-06 16:02:57 +08:00
|
|
|
enum controlField {
|
|
|
|
CTL_SYNC,
|
|
|
|
CTL_DELAY_REQ,
|
|
|
|
CTL_FOLLOW_UP,
|
|
|
|
CTL_DELAY_RESP,
|
|
|
|
CTL_MANAGEMENT,
|
|
|
|
CTL_OTHER,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ptp_header {
|
|
|
|
uint8_t tsmt; /* transportSpecific | messageType */
|
|
|
|
uint8_t ver; /* reserved | versionPTP */
|
|
|
|
UInteger16 messageLength;
|
|
|
|
UInteger8 domainNumber;
|
|
|
|
Octet reserved1;
|
|
|
|
Octet flagField[2];
|
|
|
|
Integer64 correction;
|
|
|
|
UInteger32 reserved2;
|
|
|
|
struct PortIdentity sourcePortIdentity;
|
|
|
|
UInteger16 sequenceId;
|
|
|
|
UInteger8 control;
|
|
|
|
Integer8 logMessageInterval;
|
|
|
|
} PACKED;
|
|
|
|
|
|
|
|
struct announce_msg {
|
|
|
|
struct ptp_header hdr;
|
|
|
|
struct Timestamp originTimestamp;
|
|
|
|
Integer16 currentUtcOffset;
|
|
|
|
Octet reserved;
|
|
|
|
UInteger8 grandmasterPriority1;
|
|
|
|
struct ClockQuality grandmasterClockQuality;
|
|
|
|
UInteger8 grandmasterPriority2;
|
|
|
|
struct ClockIdentity grandmasterIdentity;
|
|
|
|
UInteger16 stepsRemoved;
|
|
|
|
Enumeration8 timeSource;
|
2012-06-04 00:55:42 +08:00
|
|
|
uint8_t suffix[0];
|
2011-11-06 16:02:57 +08:00
|
|
|
} PACKED;
|
|
|
|
|
|
|
|
struct sync_msg {
|
|
|
|
struct ptp_header hdr;
|
|
|
|
struct Timestamp originTimestamp;
|
|
|
|
} PACKED;
|
|
|
|
|
|
|
|
struct delay_req_msg {
|
|
|
|
struct ptp_header hdr;
|
|
|
|
struct Timestamp originTimestamp;
|
2017-11-26 03:03:07 +08:00
|
|
|
uint8_t suffix[0];
|
2011-11-06 16:02:57 +08:00
|
|
|
} PACKED;
|
|
|
|
|
|
|
|
struct follow_up_msg {
|
|
|
|
struct ptp_header hdr;
|
|
|
|
struct Timestamp preciseOriginTimestamp;
|
2012-06-04 00:55:42 +08:00
|
|
|
uint8_t suffix[0];
|
2011-11-06 16:02:57 +08:00
|
|
|
} PACKED;
|
|
|
|
|
|
|
|
struct delay_resp_msg {
|
|
|
|
struct ptp_header hdr;
|
|
|
|
struct Timestamp receiveTimestamp;
|
|
|
|
struct PortIdentity requestingPortIdentity;
|
2012-06-04 00:55:42 +08:00
|
|
|
uint8_t suffix[0];
|
2011-11-06 16:02:57 +08:00
|
|
|
} PACKED;
|
|
|
|
|
|
|
|
struct pdelay_req_msg {
|
|
|
|
struct ptp_header hdr;
|
|
|
|
struct Timestamp originTimestamp;
|
|
|
|
struct PortIdentity reserved;
|
|
|
|
} PACKED;
|
|
|
|
|
|
|
|
struct pdelay_resp_msg {
|
|
|
|
struct ptp_header hdr;
|
|
|
|
struct Timestamp requestReceiptTimestamp;
|
|
|
|
struct PortIdentity requestingPortIdentity;
|
|
|
|
} PACKED;
|
|
|
|
|
|
|
|
struct pdelay_resp_fup_msg {
|
|
|
|
struct ptp_header hdr;
|
2012-04-02 22:45:44 +08:00
|
|
|
struct Timestamp responseOriginTimestamp;
|
2011-11-06 16:02:57 +08:00
|
|
|
struct PortIdentity requestingPortIdentity;
|
2012-06-04 00:55:42 +08:00
|
|
|
uint8_t suffix[0];
|
2011-11-06 16:02:57 +08:00
|
|
|
} PACKED;
|
|
|
|
|
2012-06-04 01:11:36 +08:00
|
|
|
struct signaling_msg {
|
|
|
|
struct ptp_header hdr;
|
|
|
|
struct PortIdentity targetPortIdentity;
|
|
|
|
uint8_t suffix[0];
|
|
|
|
} PACKED;
|
|
|
|
|
|
|
|
struct management_msg {
|
|
|
|
struct ptp_header hdr;
|
|
|
|
struct PortIdentity targetPortIdentity;
|
|
|
|
UInteger8 startingBoundaryHops;
|
|
|
|
UInteger8 boundaryHops;
|
|
|
|
uint8_t flags; /* reserved | actionField */
|
|
|
|
uint8_t reserved;
|
|
|
|
uint8_t suffix[0];
|
|
|
|
} PACKED;
|
|
|
|
|
2012-07-08 19:11:38 +08:00
|
|
|
struct message_data {
|
|
|
|
uint8_t buffer[1500];
|
|
|
|
} PACKED;
|
|
|
|
|
2011-11-06 16:02:57 +08:00
|
|
|
struct ptp_message {
|
|
|
|
union {
|
|
|
|
struct ptp_header header;
|
|
|
|
struct announce_msg announce;
|
|
|
|
struct sync_msg sync;
|
|
|
|
struct delay_req_msg delay_req;
|
|
|
|
struct follow_up_msg follow_up;
|
|
|
|
struct delay_resp_msg delay_resp;
|
|
|
|
struct pdelay_req_msg pdelay_req;
|
|
|
|
struct pdelay_resp_msg pdelay_resp;
|
|
|
|
struct pdelay_resp_fup_msg pdelay_resp_fup;
|
2012-06-04 01:11:36 +08:00
|
|
|
struct signaling_msg signaling;
|
|
|
|
struct management_msg management;
|
2012-07-08 19:11:38 +08:00
|
|
|
struct message_data data;
|
2011-11-06 16:02:57 +08:00
|
|
|
} PACKED;
|
|
|
|
/**/
|
2012-04-20 22:30:01 +08:00
|
|
|
int tail_room;
|
2011-11-06 16:02:57 +08:00
|
|
|
int refcnt;
|
|
|
|
TAILQ_ENTRY(ptp_message) list;
|
|
|
|
struct {
|
|
|
|
/**
|
|
|
|
* Contains the time stamp from the packet data in a
|
|
|
|
* native binary format for the host machine. The
|
|
|
|
* exact source of the time stamp's value depends on
|
|
|
|
* the message type:
|
|
|
|
*
|
|
|
|
* - announce originTimestamp
|
|
|
|
* - follow_up preciseOriginTimestamp
|
|
|
|
* - sync originTimestamp
|
|
|
|
* - delay_req originTimestamp
|
2012-04-02 23:20:04 +08:00
|
|
|
* - pdelay_resp requestReceiptTimestamp
|
|
|
|
* - pdelay_resp_fup responseOriginTimestamp
|
2011-11-06 16:02:57 +08:00
|
|
|
*/
|
|
|
|
struct timestamp pdu;
|
|
|
|
/**
|
|
|
|
* Approximate ingress time stamp using the relative
|
|
|
|
* CLOCK_MONOTONIC. Used to determine when announce
|
|
|
|
* messages have expired.
|
|
|
|
*/
|
|
|
|
struct timespec host;
|
|
|
|
} ts;
|
|
|
|
/**
|
|
|
|
* Contains the ingress time stamp obtained by the
|
|
|
|
* SO_TIMESTAMPING socket option.
|
|
|
|
*/
|
|
|
|
struct hw_timestamp hwts;
|
2014-04-22 22:00:59 +08:00
|
|
|
/**
|
|
|
|
* Contains the address this message was received from or should be
|
|
|
|
* sent to.
|
|
|
|
*/
|
|
|
|
struct address address;
|
2018-01-26 01:01:55 +08:00
|
|
|
/**
|
|
|
|
* List of TLV descriptors. Each item in the list contains
|
|
|
|
* pointers to the appended TLVs.
|
|
|
|
*/
|
|
|
|
TAILQ_HEAD(tlv_list, tlv_extra) tlv_list;
|
2011-11-06 16:02:57 +08:00
|
|
|
};
|
|
|
|
|
2012-08-02 12:33:32 +08:00
|
|
|
/**
|
|
|
|
* Obtain the action field from a management message.
|
|
|
|
* @param m A management message.
|
|
|
|
* @return The value of the action field.
|
|
|
|
*/
|
|
|
|
static inline uint8_t management_action(struct ptp_message *m)
|
|
|
|
{
|
|
|
|
return m->management.flags & 0x0f;
|
|
|
|
}
|
|
|
|
|
2011-11-06 16:02:57 +08:00
|
|
|
/**
|
|
|
|
* Test a given bit in a message's flag field.
|
|
|
|
* @param m Message to test.
|
|
|
|
* @param index Index into flag field, either 0 or 1.
|
|
|
|
* @param bit Bit mask of one bit to test.
|
|
|
|
* @return One if bit is set, zero otherwise.
|
|
|
|
*/
|
|
|
|
static inline Boolean field_is_set(struct ptp_message *m, int index, Octet bit)
|
|
|
|
{
|
|
|
|
return m->header.flagField[index] & bit ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
2018-02-24 14:43:24 +08:00
|
|
|
/**
|
|
|
|
* Append a new TLV onto a message for transmission.
|
|
|
|
*
|
|
|
|
* This is a high level API designed for the transmit path. The
|
|
|
|
* function allocates a new descriptor, initializes its .tlv field,
|
|
|
|
* and ensures that the TLV will fit into the message buffer. This
|
|
|
|
* function increments the message length field by 'length' before
|
|
|
|
* returning.
|
|
|
|
*
|
|
|
|
* @param msg A message obtained using msg_allocate(). At a mininum,
|
|
|
|
* the message type and length fields must set by the caller.
|
|
|
|
* @param length The length of the TLV to append.
|
|
|
|
* @return A pointer to a TLV descriptor on success or NULL otherwise.
|
|
|
|
*/
|
|
|
|
struct tlv_extra *msg_tlv_append(struct ptp_message *msg, int length);
|
|
|
|
|
2018-02-08 02:58:39 +08:00
|
|
|
/**
|
|
|
|
* Place a TLV descriptor into a message's list of TLVs.
|
|
|
|
*
|
|
|
|
* @param msg A message obtained using msg_allocate().
|
|
|
|
* @param extra The TLV to be added to the list.
|
|
|
|
*/
|
|
|
|
void msg_tlv_attach(struct ptp_message *msg, struct tlv_extra *extra);
|
|
|
|
|
2018-07-10 17:31:45 +08:00
|
|
|
/*
|
|
|
|
* Return the number of TLVs attached to a message.
|
|
|
|
* @param msg A message obtained using @ref msg_allocate().
|
|
|
|
* @return The number of attached TLVs.
|
|
|
|
*/
|
|
|
|
int msg_tlv_count(struct ptp_message *msg);
|
|
|
|
|
2012-07-28 04:17:56 +08:00
|
|
|
/**
|
|
|
|
* Obtain the transportSpecific field from a message.
|
|
|
|
* @param m Message to test.
|
|
|
|
* @return The value of the transportSpecific field. Note that the
|
|
|
|
* value is returned unshifted, in the upper nibble.
|
|
|
|
*/
|
|
|
|
static inline UInteger8 msg_transport_specific(struct ptp_message *m)
|
|
|
|
{
|
|
|
|
return m->header.tsmt & 0xf0;
|
|
|
|
}
|
|
|
|
|
2011-11-06 16:02:57 +08:00
|
|
|
/**
|
|
|
|
* Obtain the message type.
|
|
|
|
* @param m Message to test.
|
|
|
|
* @return The value of the messageType field.
|
|
|
|
*/
|
2018-11-09 15:42:58 +08:00
|
|
|
static inline int msg_type(const struct ptp_message *m)
|
2011-11-06 16:02:57 +08:00
|
|
|
{
|
|
|
|
return m->header.tsmt & 0x0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Allocate a new message instance.
|
|
|
|
*
|
|
|
|
* Messages are reference counted, and newly allocated messages have a
|
|
|
|
* reference count of one. Allocated messages are freed using the
|
|
|
|
* function @ref msg_put().
|
|
|
|
*
|
|
|
|
* @return Pointer to a message on success, NULL otherwise.
|
|
|
|
*/
|
|
|
|
struct ptp_message *msg_allocate(void);
|
|
|
|
|
2012-08-28 03:09:10 +08:00
|
|
|
/**
|
|
|
|
* Release all of the memory in the message cache.
|
|
|
|
*/
|
|
|
|
void msg_cleanup(void);
|
|
|
|
|
2018-03-18 14:02:01 +08:00
|
|
|
/**
|
|
|
|
* Duplicate a message instance.
|
|
|
|
*
|
|
|
|
* This function accepts a message in network byte order and returns a
|
|
|
|
* duplicate in host byte.
|
|
|
|
*
|
|
|
|
* Messages are reference counted, and newly allocated messages have a
|
|
|
|
* reference count of one. Allocated messages are freed using the
|
|
|
|
* function @ref msg_put().
|
|
|
|
*
|
|
|
|
* @param msg A message obtained using @ref msg_allocate().
|
|
|
|
* The passed message must be in network byte order, not
|
|
|
|
* having been passed to @ref msg_post_recv().
|
|
|
|
*
|
|
|
|
* @return Pointer to a message on success, NULL otherwise.
|
|
|
|
* The returned message will be in host byte order, having
|
|
|
|
* been passed to @ref msg_post_recv().
|
|
|
|
*/
|
|
|
|
struct ptp_message *msg_duplicate(struct ptp_message *msg, int cnt);
|
|
|
|
|
2011-11-06 16:02:57 +08:00
|
|
|
/**
|
|
|
|
* Obtain a reference to a message, increasing its reference count by one.
|
|
|
|
* @param m A message obtained using @ref msg_allocate().
|
|
|
|
*/
|
|
|
|
void msg_get(struct ptp_message *m);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process messages after reception.
|
2013-01-20 17:40:52 +08:00
|
|
|
* @param m A message obtained using @ref msg_allocate().
|
|
|
|
* @param cnt The size of 'm' in bytes.
|
2011-11-06 16:02:57 +08:00
|
|
|
* @return Zero on success, non-zero if the message is invalid.
|
|
|
|
*/
|
|
|
|
int msg_post_recv(struct ptp_message *m, int cnt);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepare messages for transmission.
|
|
|
|
* @param m A message obtained using @ref msg_allocate().
|
|
|
|
* @return Zero on success, non-zero if the message is invalid.
|
|
|
|
*/
|
|
|
|
int msg_pre_send(struct ptp_message *m);
|
|
|
|
|
2013-03-28 23:30:17 +08:00
|
|
|
/**
|
|
|
|
* Print messages for debugging purposes.
|
|
|
|
* @param type Value of the messageType field as returned by @ref msg_type().
|
|
|
|
* @return String describing the message type.
|
|
|
|
*/
|
2014-02-08 00:52:03 +08:00
|
|
|
const char *msg_type_string(int type);
|
2013-03-28 23:30:17 +08:00
|
|
|
|
2011-11-06 16:02:57 +08:00
|
|
|
/**
|
|
|
|
* Print messages for debugging purposes.
|
|
|
|
* @param m A message obtained using @ref msg_allocate().
|
|
|
|
* @param fp An open file pointer.
|
|
|
|
*/
|
|
|
|
void msg_print(struct ptp_message *m, FILE *fp);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Release a reference to a message, decreasing its reference count by one.
|
|
|
|
* @param m A message obtained using @ref msg_allocate().
|
|
|
|
*/
|
|
|
|
void msg_put(struct ptp_message *m);
|
|
|
|
|
2012-03-11 16:53:28 +08:00
|
|
|
/**
|
|
|
|
* Test whether an event message received a valid SO_TIMESTAMPING time stamp.
|
|
|
|
* @param m Message to test.
|
|
|
|
* @return One if the message is an event without a time stamp, zero otherwise.
|
|
|
|
*/
|
|
|
|
int msg_sots_missing(struct ptp_message *m);
|
|
|
|
|
2014-12-06 06:44:38 +08:00
|
|
|
/**
|
|
|
|
* Test whether a message has a valid SO_TIMESTAMPING time stamp.
|
|
|
|
* @param m Message to test.
|
|
|
|
* @return One if the message has a valid time stamp, zero otherwise.
|
|
|
|
*/
|
|
|
|
static inline int msg_sots_valid(struct ptp_message *m)
|
|
|
|
{
|
2018-03-12 20:36:30 +08:00
|
|
|
return !tmv_is_zero(m->hwts.ts);
|
2014-12-06 06:44:38 +08:00
|
|
|
}
|
|
|
|
|
2018-04-03 11:19:26 +08:00
|
|
|
/**
|
|
|
|
* Test whether a message is a unicast message.
|
|
|
|
* @param m Message to test.
|
|
|
|
* @return One if the message is unicast, zero otherwise.
|
|
|
|
*/
|
|
|
|
static inline Boolean msg_unicast(struct ptp_message *m)
|
|
|
|
{
|
|
|
|
return field_is_set(m, 0, UNICAST);
|
|
|
|
}
|
|
|
|
|
2012-07-28 04:34:34 +08:00
|
|
|
/**
|
|
|
|
* Work around buggy 802.1AS switches.
|
|
|
|
*/
|
|
|
|
extern int assume_two_step;
|
|
|
|
|
2011-11-06 16:02:57 +08:00
|
|
|
/**
|
|
|
|
* Test whether a message is one-step message.
|
|
|
|
* @param m Message to test.
|
|
|
|
* @return One if the message is a one-step, zero otherwise.
|
|
|
|
*/
|
|
|
|
static inline Boolean one_step(struct ptp_message *m)
|
|
|
|
{
|
2012-07-28 04:34:34 +08:00
|
|
|
if (assume_two_step)
|
|
|
|
return 0;
|
2011-11-06 16:02:57 +08:00
|
|
|
return !field_is_set(m, 0, TWO_STEP);
|
|
|
|
}
|
|
|
|
|
2012-08-10 02:33:47 +08:00
|
|
|
/**
|
|
|
|
* Convert a 64 bit word into network byte order.
|
|
|
|
*/
|
2018-07-10 17:55:44 +08:00
|
|
|
static inline int64_t host2net64(int64_t val)
|
|
|
|
{
|
|
|
|
return __cpu_to_be64(val);
|
|
|
|
}
|
2012-08-10 02:33:47 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert a 64 bit word into host byte order.
|
|
|
|
*/
|
2018-07-10 17:55:44 +08:00
|
|
|
static inline int64_t net2host64(int64_t val)
|
|
|
|
{
|
|
|
|
return __be64_to_cpu(val);
|
|
|
|
}
|
2012-08-10 02:33:47 +08:00
|
|
|
|
2011-11-06 16:02:57 +08:00
|
|
|
#endif
|