Some messages do not need a new authentication tlv attached but instead only require the existing tlv to be updated because a protected field was edited. These include messages being forward via a transparent clock and management messages.
Introduce sad_update_auth_tlv() to search for existing authentication tlvs, confirm their spp/security parameters are known, and regenerate the icv. Because this function still requires valid tlv pointers, add msg_tlv_copy() to copy the pointers from the formatted message to the raw message duplicate. In addition add various calls to e2e_tc/p2p_tc to match port.c Signed-off-by: Clay Kaiser <clay.kai...@ibm.com> --- clock.c | 2 ++ e2e_tc.c | 24 +++++++++++++++++++++++- msg.c | 24 +++++++++++++++++++++++- msg.h | 14 +++++++++++++- p2p_tc.c | 25 ++++++++++++++++++++++++- sad.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ sad.h | 11 +++++++++++ tc.c | 7 +++++++ 8 files changed, 156 insertions(+), 4 deletions(-) diff --git a/clock.c b/clock.c index 51c779b..785384b 100644 --- a/clock.c +++ b/clock.c @@ -337,6 +337,7 @@ void clock_send_notification(struct clock *c, struct ptp_message *msg, msg->management.targetPortIdentity.portNumber = htons(s->targetPortIdentity.portNumber); msg->address = s->addr; + sad_update_auth_tlv(clock_config(c), msg); port_forward_to(uds, msg); } } @@ -1588,6 +1589,7 @@ static int clock_do_forward_mgmt(struct clock *c, /* delay calling msg_pre_send until * actually forwarding */ msg_pre_send(msg); + sad_update_auth_tlv(clock_config(c), msg); *pre_sent = 1; } return port_forward(out, msg); diff --git a/e2e_tc.c b/e2e_tc.c index 2f8e821..8ca87f5 100644 --- a/e2e_tc.c +++ b/e2e_tc.c @@ -22,6 +22,7 @@ #include "port_private.h" #include "print.h" #include "rtnl.h" +#include "sad.h" #include "tc.h" void e2e_dispatch(struct port *p, enum fsm_event event, int mdiff) @@ -50,6 +51,7 @@ void e2e_dispatch(struct port *p, enum fsm_event event, int mdiff) case PS_FAULTY: case PS_DISABLED: port_disable(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); break; case PS_LISTENING: port_set_announce_tmo(p); @@ -60,6 +62,7 @@ void e2e_dispatch(struct port *p, enum fsm_event event, int mdiff) break; case PS_MASTER: case PS_GRAND_MASTER: + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); break; case PS_PASSIVE: port_set_announce_tmo(p); @@ -67,6 +70,7 @@ void e2e_dispatch(struct port *p, enum fsm_event event, int mdiff) case PS_UNCALIBRATED: flush_last_sync(p); flush_delay_req(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); /* fall through */ case PS_SLAVE: port_set_announce_tmo(p); @@ -76,7 +80,7 @@ void e2e_dispatch(struct port *p, enum fsm_event event, int mdiff) enum fsm_event e2e_event(struct port *p, int fd_index) { - int cnt, fd = p->fda.fd[fd_index]; + int cnt, fd = p->fda.fd[fd_index], err; enum fsm_event event = EV_NONE; struct ptp_message *msg, *dup; @@ -160,9 +164,27 @@ enum fsm_event e2e_event(struct port *p, int fd_index) msg_put(msg); return EV_NONE; } + msg_tlv_copy(dup, msg); if (tc_ignore(p, dup)) { msg_put(dup); dup = NULL; + } else { + err = sad_process_auth(clock_config(p->clock), p->spp, dup, msg); + if (err) { + switch (err) { + case -EBADMSG: + pr_err("%s: bad message", p->log_name); + break; + case -EPROTO: + pr_debug("%s: ignoring message", p->log_name); + break; + } + msg_put(msg); + if (dup) { + msg_put(dup); + } + return EV_NONE; + } } switch (msg_type(msg)) { diff --git a/msg.c b/msg.c index c82a5cb..5181570 100644 --- a/msg.c +++ b/msg.c @@ -189,6 +189,8 @@ static int suffix_post_recv(struct ptp_message *msg, int len) if (!ptr) return 0; + msg_tlv_recycle(msg); + while (len >= sizeof(struct TLV)) { extra = tlv_extra_alloc(); if (!extra) { @@ -233,7 +235,6 @@ static void suffix_pre_send(struct ptp_message *msg) tlv->type = htons(tlv->type); tlv->length = htons(tlv->length); } - msg_tlv_recycle(msg); } static void timestamp_post_recv(struct ptp_message *m, struct Timestamp *ts) @@ -516,6 +517,27 @@ int msg_tlv_count(struct ptp_message *msg) return count; } +int msg_tlv_copy(struct ptp_message *msg, struct ptp_message *dup) { + struct tlv_extra *extra, *dup_extra; + struct TLV *tlv; + + if (msg_type(msg) != msg_type(dup)) { + return -1; + } + if (msg->header.messageLength != ntohs(dup->header.messageLength)) { + return -1; + } + + TAILQ_FOREACH(extra, &msg->tlv_list, list) { + tlv = (void *) extra->tlv - (void *) msg + (void *) dup; + dup_extra = tlv_extra_alloc(); + dup_extra->tlv = tlv; + msg_tlv_attach(dup, dup_extra); + } + + return 0; +} + const char *msg_type_string(int type) { switch (type) { diff --git a/msg.h b/msg.h index 044b92b..0b4c5f0 100644 --- a/msg.h +++ b/msg.h @@ -309,6 +309,18 @@ struct tlv_extra *msg_tlv_append(struct ptp_message *msg, int length); */ void msg_tlv_attach(struct ptp_message *msg, struct tlv_extra *extra); +/** + * Copy list of TLVs from message that has gone through @ref msg_post_recv() + * to a network byte order duplicate message. This is useful for TC applications + * where any auth tlvs must be updated on the raw forwarded messages. + * @param msg A message obtained using @ref msg_allocate(). + * The passed message must have been passed to @ref msg_post_recv() + * in order to have tlv pointers attached. + * @param dup A duplicate of msg that is still in network byte order. + * @return -1 if the messages do not match, otherwise 0 + */ +int msg_tlv_copy(struct ptp_message *msg, struct ptp_message *dup); + /* * Return the number of TLVs attached to a message. * @param msg A message obtained using @ref msg_allocate(). @@ -366,7 +378,7 @@ void msg_cleanup(void); * @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(). - * @param cnt The size of 'msg' in bytes. set to zero when + * @param cnt The size of msg in bytes. set to zero when * @ref msg_post_recv() is not required (icv calculation) * @return Pointer to a message on success, NULL otherwise. * The returned message will be in host byte order, having diff --git a/p2p_tc.c b/p2p_tc.c index 75cb3b9..1289563 100644 --- a/p2p_tc.c +++ b/p2p_tc.c @@ -22,6 +22,7 @@ #include "port_private.h" #include "print.h" #include "rtnl.h" +#include "sad.h" #include "tc.h" static int p2p_delay_request(struct port *p) @@ -69,6 +70,7 @@ void p2p_dispatch(struct port *p, enum fsm_event event, int mdiff) case PS_FAULTY: case PS_DISABLED: port_disable(p); + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); break; case PS_LISTENING: port_set_announce_tmo(p); @@ -79,11 +81,14 @@ void p2p_dispatch(struct port *p, enum fsm_event event, int mdiff) break; case PS_MASTER: case PS_GRAND_MASTER: + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); break; case PS_PASSIVE: port_set_announce_tmo(p); break; case PS_UNCALIBRATED: + sad_set_last_seqid(clock_config(p->clock), p->spp, 0); + /* fall through */ case PS_SLAVE: port_set_announce_tmo(p); break; @@ -92,7 +97,7 @@ void p2p_dispatch(struct port *p, enum fsm_event event, int mdiff) enum fsm_event p2p_event(struct port *p, int fd_index) { - int cnt, fd = p->fda.fd[fd_index]; + int cnt, fd = p->fda.fd[fd_index], err; enum fsm_event event = EV_NONE; struct ptp_message *msg, *dup; @@ -163,9 +168,27 @@ enum fsm_event p2p_event(struct port *p, int fd_index) msg_put(msg); return EV_NONE; } + msg_tlv_copy(dup, msg); if (tc_ignore(p, dup)) { msg_put(dup); dup = NULL; + } else { + err = sad_process_auth(clock_config(p->clock), p->spp, dup, msg); + if (err) { + switch (err) { + case -EBADMSG: + pr_err("%s: bad message", p->log_name); + break; + case -EPROTO: + pr_debug("%s: ignoring message", p->log_name); + break; + } + msg_put(msg); + if (dup) { + msg_put(dup); + } + return EV_NONE; + } } switch (msg_type(msg)) { diff --git a/sad.c b/sad.c index ee8ead4..9849934 100644 --- a/sad.c +++ b/sad.c @@ -100,6 +100,59 @@ static int sad_generate_icv(struct security_association *sa, return icv_len; } +int sad_update_auth_tlv(struct config *cfg, + struct ptp_message *msg) +{ + struct tlv_extra *extra; + struct authentication_tlv *auth; + struct security_association *sa; + struct security_association_key *key; + void *sequenceNo, *res, *icv; + /* update any/all authentication tlvs now */ + TAILQ_FOREACH(extra, &msg->tlv_list, list) { + if (ntohs(extra->tlv->type) != TLV_AUTHENTICATION) { + continue; + } + auth = (struct authentication_tlv *) extra->tlv; + /* retrieve sa specified by spp in tlv */ + sa = sad_get_association(cfg, auth->spp); + if (sa == NULL) { + return -1; + } + /* verify res and seqnum field indicators match expectations */ + if ((sa->res_ind != (auth->secParamIndicator & 0x1)) || + (sa->seqnum_ind != (auth->secParamIndicator & 0x2))) { + pr_debug("sa %u: unable to update auth tlv," + " sec param %d does not match", + sa->spp, auth->secParamIndicator); + return -1; + } + /* retrieve key specified by keyid in tlv */ + key = sad_get_key(sa, ntohl(auth->keyID)); + if (key == NULL) { + pr_debug("sa %u: unable to update auth tlv," + " unable to retrieve key %u", + sa->spp, ntohl(auth->keyID)); + return -1; + } + /* confirm tlv length to be generated matches what already exists */ + if (ntohs(auth->length) != sad_get_auth_tlv_len(sa, key->icv.len) - 4) { + pr_debug("sa %u: unable to update auth tlv," + " length is not maintained", sa->spp); + return -1; + } + /* set pointers to extra data used for icv generation */ + sequenceNo = auth->data; + res = sequenceNo + (sa->seqnum_ind ? sa->seqnum_len : 0); + icv = res + (sa->res_ind ? sa->res_len : 0); + if (!sad_generate_icv(sa, key, msg, icv)) { + return -1; + } + } + + return 0; +} + int sad_append_auth_tlv(struct config *cfg, int spp, UInteger32 key_id, struct ptp_message *msg) { diff --git a/sad.h b/sad.h index 7a5051d..6c11ab4 100644 --- a/sad.h +++ b/sad.h @@ -37,6 +37,17 @@ struct security_association { UInteger16 last_seqid; }; +/** + * Update authentication tlvs. Pass a network byte order message that + * still contains tlv pointers. Attempt to recalcute icv for each + * authentication tlv attached. + * @param cfg pointer to config that contains sad + * @param msg msg that the authentication tlvs should be updated for + * @return -1 if sa/key is unknown, otherwise 0 + */ +int sad_update_auth_tlv(struct config *cfg, + struct ptp_message *msg); + /** * Append authentication tlv. Includes msg_pre_send() to put message in * network byte order so the icv can be calculated. diff --git a/tc.c b/tc.c index 1847041..810b7e7 100644 --- a/tc.c +++ b/tc.c @@ -20,6 +20,7 @@ #include "port.h" #include "print.h" +#include "sad.h" #include "tc.h" #include "tmv.h" @@ -162,6 +163,7 @@ static void tc_complete_response(struct port *q, struct port *p, c1 = net2host64(resp->header.correction); c2 = c1 + tmv_to_TimeInterval(residence); resp->header.correction = host2net64(c2); + sad_update_auth_tlv(clock_config(q->clock), resp); cnt = transport_send(p->trp, &p->fda, TRANS_GENERAL, resp); if (cnt <= 0) { pr_err("tc failed to forward response on %s", p->log_name); @@ -223,6 +225,7 @@ static void tc_complete_syfup(struct port *q, struct port *p, c2 += tmv_to_TimeInterval(q->peer_delay); c2 += q->asymmetry; fup->header.correction = host2net64(c2); + sad_update_auth_tlv(clock_config(q->clock), fup); cnt = transport_send(p->trp, &p->fda, TRANS_GENERAL, fup); if (cnt <= 0) { pr_err("tc failed to forward follow up on %s", p->log_name); @@ -389,6 +392,7 @@ int tc_forward(struct port *q, struct ptp_message *msg) if (q->tc_spanning_tree && msg_type(msg) == ANNOUNCE) { steps_removed = ntohs(msg->announce.stepsRemoved); msg->announce.stepsRemoved = htons(1 + steps_removed); + sad_update_auth_tlv(clock_config(q->clock), msg); } for (p = clock_first_port(q->clock); p; p = LIST_NEXT(p, list)) { @@ -458,7 +462,10 @@ int tc_fwd_sync(struct port *q, struct ptp_message *msg) fup->header.sequenceId = msg->header.sequenceId; fup->header.logMessageInterval = msg->header.logMessageInterval; fup->follow_up.preciseOriginTimestamp = msg->sync.originTimestamp; + sad_append_auth_tlv(clock_config(q->clock), q->spp, + q->active_key_id, fup); msg->header.flagField[0] |= TWO_STEP; + sad_update_auth_tlv(clock_config(q->clock), msg); } err = tc_fwd_event(q, msg); if (err) { -- 2.42.1 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel