support TLVs with flexible size
These flexible TLVs don't need to be represented as a single packed struct directly in the message buffer. Instead a separate struct contains pointers to the individual parts of the TLV in the message buffer. The flexible TLV can only be the last TLV in a message. Signed-off-by: Geoff Salmon <gsalmon@se-instruments.com>master
parent
09f8fe0e0b
commit
f4e8f5be3f
12
msg.c
12
msg.c
|
@ -144,7 +144,7 @@ static void port_id_pre_send(struct PortIdentity *pid)
|
||||||
pid->portNumber = htons(pid->portNumber);
|
pid->portNumber = htons(pid->portNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int suffix_post_recv(uint8_t *ptr, int len)
|
static int suffix_post_recv(uint8_t *ptr, int len, struct tlv_extra *last)
|
||||||
{
|
{
|
||||||
int cnt;
|
int cnt;
|
||||||
struct TLV *tlv;
|
struct TLV *tlv;
|
||||||
|
@ -166,14 +166,14 @@ static int suffix_post_recv(uint8_t *ptr, int len)
|
||||||
}
|
}
|
||||||
len -= tlv->length;
|
len -= tlv->length;
|
||||||
ptr += tlv->length;
|
ptr += tlv->length;
|
||||||
if (tlv_post_recv(tlv)) {
|
if (tlv_post_recv(tlv, len ? NULL : last)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void suffix_pre_send(uint8_t *ptr, int cnt)
|
static void suffix_pre_send(uint8_t *ptr, int cnt, struct tlv_extra *last)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct TLV *tlv;
|
struct TLV *tlv;
|
||||||
|
@ -183,7 +183,7 @@ static void suffix_pre_send(uint8_t *ptr, int cnt)
|
||||||
|
|
||||||
for (i = 0; i < cnt; i++) {
|
for (i = 0; i < cnt; i++) {
|
||||||
tlv = (struct TLV *) ptr;
|
tlv = (struct TLV *) ptr;
|
||||||
tlv_pre_send(tlv);
|
tlv_pre_send(tlv, i == cnt - 1 ? last : NULL);
|
||||||
ptr += sizeof(struct TLV) + tlv->length;
|
ptr += sizeof(struct TLV) + tlv->length;
|
||||||
tlv->type = htons(tlv->type);
|
tlv->type = htons(tlv->type);
|
||||||
tlv->length = htons(tlv->length);
|
tlv->length = htons(tlv->length);
|
||||||
|
@ -344,7 +344,7 @@ int msg_post_recv(struct ptp_message *m, int cnt)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
m->tlv_count = suffix_post_recv(suffix, cnt - pdulen);
|
m->tlv_count = suffix_post_recv(suffix, cnt - pdulen, &m->last_tlv);
|
||||||
if (m->tlv_count == -1) {
|
if (m->tlv_count == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -401,7 +401,7 @@ int msg_pre_send(struct ptp_message *m)
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
suffix_pre_send(suffix, m->tlv_count);
|
suffix_pre_send(suffix, m->tlv_count, &m->last_tlv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
msg.h
7
msg.h
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "ddt.h"
|
#include "ddt.h"
|
||||||
#include "transport.h"
|
#include "transport.h"
|
||||||
|
#include "tlv.h"
|
||||||
|
|
||||||
#define PTP_VERSION 2
|
#define PTP_VERSION 2
|
||||||
|
|
||||||
|
@ -204,6 +205,12 @@ struct ptp_message {
|
||||||
* Contains the number of TLVs in the suffix.
|
* Contains the number of TLVs in the suffix.
|
||||||
*/
|
*/
|
||||||
int tlv_count;
|
int tlv_count;
|
||||||
|
/**
|
||||||
|
* Used to hold the data of the last TLV in the message when
|
||||||
|
* the layout of the TLV makes it difficult to access the data
|
||||||
|
* directly from the message's buffer.
|
||||||
|
*/
|
||||||
|
struct tlv_extra last_tlv;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
24
tlv.c
24
tlv.c
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "port.h"
|
#include "port.h"
|
||||||
#include "tlv.h"
|
#include "tlv.h"
|
||||||
|
#include "msg.h"
|
||||||
|
|
||||||
#define TLV_LENGTH_INVALID(tlv, type) \
|
#define TLV_LENGTH_INVALID(tlv, type) \
|
||||||
(tlv->length < sizeof(struct type) - sizeof(struct TLV))
|
(tlv->length < sizeof(struct type) - sizeof(struct TLV))
|
||||||
|
@ -41,7 +42,8 @@ static void scaled_ns_h2n(ScaledNs *sns)
|
||||||
sns->fractional_nanoseconds = htons(sns->fractional_nanoseconds);
|
sns->fractional_nanoseconds = htons(sns->fractional_nanoseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mgt_post_recv(struct management_tlv *m, uint16_t data_len)
|
static int mgt_post_recv(struct management_tlv *m, uint16_t data_len,
|
||||||
|
struct tlv_extra *extra)
|
||||||
{
|
{
|
||||||
struct defaultDS *dds;
|
struct defaultDS *dds;
|
||||||
struct currentDS *cds;
|
struct currentDS *cds;
|
||||||
|
@ -49,6 +51,7 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len)
|
||||||
struct timePropertiesDS *tp;
|
struct timePropertiesDS *tp;
|
||||||
struct portDS *p;
|
struct portDS *p;
|
||||||
struct time_status_np *tsn;
|
struct time_status_np *tsn;
|
||||||
|
int extra_len = 0;
|
||||||
switch (m->id) {
|
switch (m->id) {
|
||||||
case DEFAULT_DATA_SET:
|
case DEFAULT_DATA_SET:
|
||||||
if (data_len != sizeof(struct defaultDS))
|
if (data_len != sizeof(struct defaultDS))
|
||||||
|
@ -105,12 +108,18 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len)
|
||||||
tsn->gmPresent = ntohl(tsn->gmPresent);
|
tsn->gmPresent = ntohl(tsn->gmPresent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (extra_len) {
|
||||||
|
if (extra_len % 2)
|
||||||
|
extra_len++;
|
||||||
|
if (extra_len + sizeof(m->id) != m->length)
|
||||||
|
goto bad_length;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
bad_length:
|
bad_length:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mgt_pre_send(struct management_tlv *m)
|
static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra)
|
||||||
{
|
{
|
||||||
struct defaultDS *dds;
|
struct defaultDS *dds;
|
||||||
struct currentDS *cds;
|
struct currentDS *cds;
|
||||||
|
@ -209,12 +218,15 @@ static void org_pre_send(struct organization_tlv *org)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int tlv_post_recv(struct TLV *tlv)
|
int tlv_post_recv(struct TLV *tlv, struct tlv_extra *extra)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
struct management_tlv *mgt;
|
struct management_tlv *mgt;
|
||||||
struct management_error_status *mes;
|
struct management_error_status *mes;
|
||||||
struct path_trace_tlv *ptt;
|
struct path_trace_tlv *ptt;
|
||||||
|
struct tlv_extra dummy_extra;
|
||||||
|
if (!extra)
|
||||||
|
extra = &dummy_extra;
|
||||||
|
|
||||||
switch (tlv->type) {
|
switch (tlv->type) {
|
||||||
case TLV_MANAGEMENT:
|
case TLV_MANAGEMENT:
|
||||||
|
@ -223,7 +235,7 @@ int tlv_post_recv(struct TLV *tlv)
|
||||||
mgt = (struct management_tlv *) tlv;
|
mgt = (struct management_tlv *) tlv;
|
||||||
mgt->id = ntohs(mgt->id);
|
mgt->id = ntohs(mgt->id);
|
||||||
if (tlv->length > sizeof(mgt->id))
|
if (tlv->length > sizeof(mgt->id))
|
||||||
result = mgt_post_recv(mgt, tlv->length - sizeof(mgt->id));
|
result = mgt_post_recv(mgt, tlv->length - sizeof(mgt->id), extra);
|
||||||
break;
|
break;
|
||||||
case TLV_MANAGEMENT_ERROR_STATUS:
|
case TLV_MANAGEMENT_ERROR_STATUS:
|
||||||
if (TLV_LENGTH_INVALID(tlv, management_error_status))
|
if (TLV_LENGTH_INVALID(tlv, management_error_status))
|
||||||
|
@ -261,7 +273,7 @@ bad_length:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tlv_pre_send(struct TLV *tlv)
|
void tlv_pre_send(struct TLV *tlv, struct tlv_extra *extra)
|
||||||
{
|
{
|
||||||
struct management_tlv *mgt;
|
struct management_tlv *mgt;
|
||||||
struct management_error_status *mes;
|
struct management_error_status *mes;
|
||||||
|
@ -270,7 +282,7 @@ void tlv_pre_send(struct TLV *tlv)
|
||||||
case TLV_MANAGEMENT:
|
case TLV_MANAGEMENT:
|
||||||
mgt = (struct management_tlv *) tlv;
|
mgt = (struct management_tlv *) tlv;
|
||||||
if (tlv->length > sizeof(mgt->id))
|
if (tlv->length > sizeof(mgt->id))
|
||||||
mgt_pre_send(mgt);
|
mgt_pre_send(mgt, extra);
|
||||||
mgt->id = htons(mgt->id);
|
mgt->id = htons(mgt->id);
|
||||||
break;
|
break;
|
||||||
case TLV_MANAGEMENT_ERROR_STATUS:
|
case TLV_MANAGEMENT_ERROR_STATUS:
|
||||||
|
|
16
tlv.h
16
tlv.h
|
@ -21,7 +21,6 @@
|
||||||
#define HAVE_TLV_H
|
#define HAVE_TLV_H
|
||||||
|
|
||||||
#include "ddt.h"
|
#include "ddt.h"
|
||||||
#include "msg.h"
|
|
||||||
|
|
||||||
/* TLV types */
|
/* TLV types */
|
||||||
#define TLV_MANAGEMENT 0x0001
|
#define TLV_MANAGEMENT 0x0001
|
||||||
|
@ -177,17 +176,28 @@ struct time_status_np {
|
||||||
struct ClockIdentity gmIdentity;
|
struct ClockIdentity gmIdentity;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
|
struct tlv_extra {
|
||||||
|
union {
|
||||||
|
/* Empty for now, but will contain structs for the
|
||||||
|
* TLVs that use the tlv_extra support. */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts recognized value sub-fields into host byte order.
|
* Converts recognized value sub-fields into host byte order.
|
||||||
* @param tlv Pointer to a Type Length Value field.
|
* @param tlv Pointer to a Type Length Value field.
|
||||||
|
* @param extra Additional struct where data from tlv will be saved,
|
||||||
|
* can be NULL.
|
||||||
* @return Zero if successful, otherwise non-zero
|
* @return Zero if successful, otherwise non-zero
|
||||||
*/
|
*/
|
||||||
int tlv_post_recv(struct TLV *tlv);
|
int tlv_post_recv(struct TLV *tlv, struct tlv_extra *extra);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts recognized value sub-fields into network byte order.
|
* Converts recognized value sub-fields into network byte order.
|
||||||
* @param tlv Pointer to a Type Length Value field.
|
* @param tlv Pointer to a Type Length Value field.
|
||||||
|
* @param extra Additional struct containing tlv data to send, can be
|
||||||
|
* NULL.
|
||||||
*/
|
*/
|
||||||
void tlv_pre_send(struct TLV *tlv);
|
void tlv_pre_send(struct TLV *tlv, struct tlv_extra *extra);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue