1 /*
2 * Copyright (c) 2024 BayLibre SAS
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(ptp_msg, CONFIG_PTP_LOG_LEVEL);
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/net/udp.h>
12 #include <zephyr/net/ptp.h>
13
14 #include "clock.h"
15 #include "msg.h"
16 #include "port.h"
17 #include "tlv.h"
18 #include "transport.h"
19
20 static struct k_mem_slab msg_slab;
21
22 K_MEM_SLAB_DEFINE_STATIC(msg_slab, sizeof(struct ptp_msg), CONFIG_PTP_MSG_POLL_SIZE, 8);
23
msg_type_str(struct ptp_msg * msg)24 static const char *msg_type_str(struct ptp_msg *msg)
25 {
26 switch (ptp_msg_type(msg)) {
27 case PTP_MSG_SYNC:
28 return "Sync";
29 case PTP_MSG_DELAY_REQ:
30 return "Delay_Req";
31 case PTP_MSG_PDELAY_REQ:
32 return "Pdelay_Req";
33 case PTP_MSG_PDELAY_RESP:
34 return "Pdelay_Resp";
35 case PTP_MSG_FOLLOW_UP:
36 return "Follow_Up";
37 case PTP_MSG_DELAY_RESP:
38 return "Delay_Resp";
39 case PTP_MSG_PDELAY_RESP_FOLLOW_UP:
40 return "Pdelay_Resp_Follow_Up";
41 case PTP_MSG_ANNOUNCE:
42 return "Announce";
43 case PTP_MSG_SIGNALING:
44 return "Signaling";
45 case PTP_MSG_MANAGEMENT:
46 return "Management";
47 default:
48 return "Not recognized";
49 }
50 }
51
msg_timestamp_post_recv(struct ptp_msg * msg,struct ptp_timestamp * ts)52 static void msg_timestamp_post_recv(struct ptp_msg *msg, struct ptp_timestamp *ts)
53 {
54 msg->timestamp.protocol._sec.high = ntohs(ts->seconds_high);
55 msg->timestamp.protocol._sec.low = ntohl(ts->seconds_low);
56 msg->timestamp.protocol.nanosecond = ntohl(ts->nanoseconds);
57 }
58
msg_timestamp_pre_send(struct ptp_timestamp * ts)59 static void msg_timestamp_pre_send(struct ptp_timestamp *ts)
60 {
61 ts->seconds_high = htons(ts->seconds_high);
62 ts->seconds_low = htonl(ts->seconds_low);
63 ts->nanoseconds = htonl(ts->nanoseconds);
64 }
65
msg_port_id_post_recv(struct ptp_port_id * port_id)66 static void msg_port_id_post_recv(struct ptp_port_id *port_id)
67 {
68 port_id->port_number = ntohs(port_id->port_number);
69 }
70
msg_port_id_pre_send(struct ptp_port_id * port_id)71 static void msg_port_id_pre_send(struct ptp_port_id *port_id)
72 {
73 port_id->port_number = htons(port_id->port_number);
74 }
75
msg_header_post_recv(struct ptp_header * header)76 static int msg_header_post_recv(struct ptp_header *header)
77 {
78 if ((header->version & 0xF) != PTP_MAJOR_VERSION) {
79 /* Incompatible protocol version */
80 return -1;
81 }
82
83 header->msg_length = ntohs(header->msg_length);
84 header->correction = ntohll(header->correction);
85 header->sequence_id = ntohs(header->sequence_id);
86
87 msg_port_id_post_recv(&header->src_port_id);
88
89 return 0;
90 }
91
msg_header_pre_send(struct ptp_header * header)92 static void msg_header_pre_send(struct ptp_header *header)
93 {
94 header->msg_length = htons(header->msg_length);
95 header->correction = htonll(header->correction);
96 header->sequence_id = htons(header->sequence_id);
97
98 msg_port_id_pre_send(&header->src_port_id);
99 }
100
msg_suffix(struct ptp_msg * msg)101 static uint8_t *msg_suffix(struct ptp_msg *msg)
102 {
103 uint8_t *suffix = NULL;
104
105 switch (ptp_msg_type(msg)) {
106 case PTP_MSG_SYNC:
107 suffix = msg->sync.suffix;
108 break;
109 case PTP_MSG_DELAY_REQ:
110 suffix = msg->delay_req.suffix;
111 break;
112 case PTP_MSG_PDELAY_REQ:
113 suffix = msg->pdelay_req.suffix;
114 break;
115 case PTP_MSG_PDELAY_RESP:
116 suffix = msg->pdelay_resp.suffix;
117 break;
118 case PTP_MSG_FOLLOW_UP:
119 suffix = msg->follow_up.suffix;
120 break;
121 case PTP_MSG_DELAY_RESP:
122 suffix = msg->delay_resp.suffix;
123 break;
124 case PTP_MSG_PDELAY_RESP_FOLLOW_UP:
125 suffix = msg->pdelay_resp_follow_up.suffix;
126 break;
127 case PTP_MSG_ANNOUNCE:
128 suffix = msg->announce.suffix;
129 break;
130 case PTP_MSG_SIGNALING:
131 suffix = msg->signaling.suffix;
132 break;
133 case PTP_MSG_MANAGEMENT:
134 suffix = msg->management.suffix;
135 break;
136 }
137
138 return suffix;
139 }
140
msg_tlv_post_recv(struct ptp_msg * msg,int length)141 static int msg_tlv_post_recv(struct ptp_msg *msg, int length)
142 {
143 int suffix_len = 0, ret = 0;
144 struct ptp_tlv_container *tlv_container;
145 uint8_t *suffix = msg_suffix(msg);
146
147 if (!suffix) {
148 LOG_DBG("No TLV attached to the message");
149 return 0;
150 }
151
152 while (length >= sizeof(struct ptp_tlv)) {
153 tlv_container = ptp_tlv_alloc();
154 if (!tlv_container) {
155 return -ENOMEM;
156 }
157
158 tlv_container->tlv = (struct ptp_tlv *)suffix;
159 tlv_container->tlv->type = ntohs(tlv_container->tlv->type);
160 tlv_container->tlv->length = ntohs(tlv_container->tlv->length);
161
162 if (tlv_container->tlv->length % 2) {
163 /* IEEE 1588-2019 Section 5.3.8 - length is an even number */
164 LOG_ERR("Incorrect length of TLV");
165 ptp_tlv_free(tlv_container);
166 return -EBADMSG;
167 }
168
169 length -= sizeof(struct ptp_tlv);
170 suffix += sizeof(struct ptp_tlv);
171 suffix_len += sizeof(struct ptp_tlv);
172
173 if (tlv_container->tlv->length > length) {
174 LOG_ERR("Incorrect length of TLV");
175 ptp_tlv_free(tlv_container);
176 return -EBADMSG;
177 }
178
179 length -= tlv_container->tlv->length;
180 suffix += tlv_container->tlv->length;
181 suffix_len += tlv_container->tlv->length;
182
183 ret = ptp_tlv_post_recv(tlv_container->tlv);
184 if (ret) {
185 ptp_tlv_free(tlv_container);
186 return ret;
187 }
188
189 sys_slist_append(&msg->tlvs, &tlv_container->node);
190 }
191
192 return suffix_len;
193 }
194
msg_tlv_free(struct ptp_msg * msg)195 static void msg_tlv_free(struct ptp_msg *msg)
196 {
197 struct ptp_tlv_container *tlv_container;
198
199 for (sys_snode_t *iter = sys_slist_get(&msg->tlvs);
200 iter;
201 iter = sys_slist_get(&msg->tlvs)) {
202 tlv_container = CONTAINER_OF(iter, struct ptp_tlv_container, node);
203 ptp_tlv_free(tlv_container);
204 }
205 }
206
msg_tlv_pre_send(struct ptp_msg * msg)207 static void msg_tlv_pre_send(struct ptp_msg *msg)
208 {
209 struct ptp_tlv_container *tlv_container;
210
211 SYS_SLIST_FOR_EACH_CONTAINER(&msg->tlvs, tlv_container, node) {
212 ptp_tlv_pre_send(tlv_container->tlv);
213 }
214
215 /* No need to track TLVs attached to the message. */
216 msg_tlv_free(msg);
217 }
218
ptp_msg_alloc(void)219 struct ptp_msg *ptp_msg_alloc(void)
220 {
221 struct ptp_msg *msg = NULL;
222 int ret = k_mem_slab_alloc(&msg_slab, (void **)&msg, K_FOREVER);
223
224 if (ret) {
225 LOG_ERR("Couldn't allocate memory for the message");
226 return NULL;
227 }
228
229 memset(msg, 0, sizeof(*msg));
230 sys_slist_init(&msg->tlvs);
231 atomic_inc(&msg->ref);
232
233 return msg;
234 }
235
ptp_msg_unref(struct ptp_msg * msg)236 void ptp_msg_unref(struct ptp_msg *msg)
237 {
238 __ASSERT_NO_MSG(msg != NULL);
239
240 atomic_t val = atomic_dec(&msg->ref);
241
242 if (val > 1) {
243 return;
244 }
245
246 msg_tlv_free(msg);
247 k_mem_slab_free(&msg_slab, (void *)msg);
248 }
249
ptp_msg_ref(struct ptp_msg * msg)250 void ptp_msg_ref(struct ptp_msg *msg)
251 {
252 __ASSERT_NO_MSG(msg != NULL);
253
254 atomic_inc(&msg->ref);
255 }
256
ptp_msg_type(const struct ptp_msg * msg)257 enum ptp_msg_type ptp_msg_type(const struct ptp_msg *msg)
258 {
259 return (enum ptp_msg_type)(msg->header.type_major_sdo_id & 0xF);
260 }
261
ptp_msg_from_pkt(struct net_pkt * pkt)262 struct ptp_msg *ptp_msg_from_pkt(struct net_pkt *pkt)
263 {
264 static const size_t eth_hdr_len = IS_ENABLED(CONFIG_NET_VLAN) ?
265 sizeof(struct net_eth_vlan_hdr) :
266 sizeof(struct net_eth_hdr);
267 struct net_udp_hdr *hdr;
268 struct ptp_msg *msg;
269 int port, payload;
270
271 if (pkt->buffer->len == eth_hdr_len) {
272 /* Packet contain Ethernet header at the beginning. */
273 struct net_buf *buf;
274
275 /* remove packet temporarily. */
276 buf = pkt->buffer;
277 pkt->buffer = buf->frags;
278
279 hdr = net_udp_get_hdr(pkt, NULL);
280
281 /* insert back temporarily femoved frag. */
282 net_pkt_frag_insert(pkt, buf);
283 } else {
284 hdr = net_udp_get_hdr(pkt, NULL);
285 }
286
287 if (!hdr) {
288 LOG_ERR("Couldn't retrieve UDP header from the net packet");
289 return NULL;
290 }
291
292 payload = ntohs(hdr->len) - NET_UDPH_LEN;
293 port = ntohs(hdr->dst_port);
294
295 if (port != PTP_SOCKET_PORT_EVENT && port != PTP_SOCKET_PORT_GENERAL) {
296 LOG_ERR("Couldn't retrieve PTP message from the net packet");
297 return NULL;
298 }
299
300 msg = (struct ptp_msg *)((uintptr_t)hdr + NET_UDPH_LEN);
301
302 if (payload == ntohs(msg->header.msg_length)) {
303 return msg;
304 }
305
306 return NULL;
307 }
308
ptp_msg_pre_send(struct ptp_msg * msg)309 void ptp_msg_pre_send(struct ptp_msg *msg)
310 {
311 int64_t current;
312
313 msg_header_pre_send(&msg->header);
314
315 switch (ptp_msg_type(msg)) {
316 case PTP_MSG_SYNC:
317 break;
318 case PTP_MSG_DELAY_REQ:
319 current = k_uptime_get();
320
321 msg->timestamp.host.second = (uint64_t)(current / MSEC_PER_SEC);
322 msg->timestamp.host.nanosecond = (current % MSEC_PER_SEC) * NSEC_PER_MSEC;
323 break;
324 case PTP_MSG_PDELAY_REQ:
325 break;
326 case PTP_MSG_PDELAY_RESP:
327 msg_timestamp_pre_send(&msg->pdelay_resp.req_receipt_timestamp);
328 msg_port_id_pre_send(&msg->pdelay_resp.req_port_id);
329 break;
330 case PTP_MSG_FOLLOW_UP:
331 msg_timestamp_pre_send(&msg->follow_up.precise_origin_timestamp);
332 break;
333 case PTP_MSG_DELAY_RESP:
334 msg_timestamp_pre_send(&msg->delay_resp.receive_timestamp);
335 msg_port_id_pre_send(&msg->delay_resp.req_port_id);
336 break;
337 case PTP_MSG_PDELAY_RESP_FOLLOW_UP:
338 msg_timestamp_pre_send(&msg->pdelay_resp_follow_up.resp_origin_timestamp);
339 msg_port_id_pre_send(&msg->pdelay_resp_follow_up.req_port_id);
340 break;
341 case PTP_MSG_ANNOUNCE:
342 msg->announce.current_utc_offset = htons(msg->announce.current_utc_offset);
343 msg->announce.gm_clk_quality.offset_scaled_log_variance =
344 htons(msg->announce.gm_clk_quality.offset_scaled_log_variance);
345 msg->announce.steps_rm = htons(msg->announce.steps_rm);
346 break;
347 case PTP_MSG_SIGNALING:
348 msg_port_id_pre_send(&msg->signaling.target_port_id);
349 break;
350 case PTP_MSG_MANAGEMENT:
351 msg_port_id_pre_send(&msg->management.target_port_id);
352 break;
353 }
354
355 msg_tlv_pre_send(msg);
356 }
357
ptp_msg_post_recv(struct ptp_port * port,struct ptp_msg * msg,int cnt)358 int ptp_msg_post_recv(struct ptp_port *port, struct ptp_msg *msg, int cnt)
359 {
360 static const int msg_size[] = {
361 [PTP_MSG_SYNC] = sizeof(struct ptp_sync_msg),
362 [PTP_MSG_DELAY_REQ] = sizeof(struct ptp_delay_req_msg),
363 [PTP_MSG_PDELAY_REQ] = sizeof(struct ptp_pdelay_req_msg),
364 [PTP_MSG_PDELAY_RESP] = sizeof(struct ptp_pdelay_resp_msg),
365 [PTP_MSG_FOLLOW_UP] = sizeof(struct ptp_follow_up_msg),
366 [PTP_MSG_DELAY_RESP] = sizeof(struct ptp_delay_resp_msg),
367 [PTP_MSG_PDELAY_RESP_FOLLOW_UP] = sizeof(struct ptp_pdelay_resp_follow_up_msg),
368 [PTP_MSG_ANNOUNCE] = sizeof(struct ptp_announce_msg),
369 [PTP_MSG_SIGNALING] = sizeof(struct ptp_signaling_msg),
370 [PTP_MSG_MANAGEMENT] = sizeof(struct ptp_management_msg),
371 };
372 enum ptp_msg_type type = ptp_msg_type(msg);
373 int64_t current;
374 int tlv_len;
375
376 if (msg_size[type] > cnt) {
377 LOG_ERR("Received message with incorrect length");
378 return -EBADMSG;
379 }
380
381 if (msg_header_post_recv(&msg->header)) {
382 LOG_ERR("Received message incomplient with supported PTP version");
383 return -EBADMSG;
384 }
385
386 LOG_DBG("Port %d received %s message", port->port_ds.id.port_number, msg_type_str(msg));
387
388 switch (type) {
389 case PTP_MSG_SYNC:
390 msg_timestamp_post_recv(msg, &msg->sync.origin_timestamp);
391 break;
392 case PTP_MSG_DELAY_REQ:
393 break;
394 case PTP_MSG_PDELAY_REQ:
395 break;
396 case PTP_MSG_PDELAY_RESP:
397 msg_timestamp_post_recv(msg, &msg->pdelay_resp.req_receipt_timestamp);
398 msg_port_id_post_recv(&msg->pdelay_resp.req_port_id);
399 break;
400 case PTP_MSG_FOLLOW_UP:
401 msg_timestamp_post_recv(msg, &msg->follow_up.precise_origin_timestamp);
402 break;
403 case PTP_MSG_DELAY_RESP:
404 msg_timestamp_post_recv(msg, &msg->delay_resp.receive_timestamp);
405 msg_port_id_post_recv(&msg->delay_resp.req_port_id);
406 break;
407 case PTP_MSG_PDELAY_RESP_FOLLOW_UP:
408 msg_timestamp_post_recv(msg, &msg->pdelay_resp_follow_up.resp_origin_timestamp);
409 msg_port_id_post_recv(&msg->pdelay_resp_follow_up.req_port_id);
410 break;
411 case PTP_MSG_ANNOUNCE:
412 current = k_uptime_get();
413
414 msg->timestamp.host.second = (uint64_t)(current / MSEC_PER_SEC);
415 msg->timestamp.host.nanosecond = (current % MSEC_PER_SEC) * NSEC_PER_MSEC;
416 msg_timestamp_post_recv(msg, &msg->announce.origin_timestamp);
417 msg->announce.current_utc_offset = ntohs(msg->announce.current_utc_offset);
418 msg->announce.gm_clk_quality.offset_scaled_log_variance =
419 ntohs(msg->announce.gm_clk_quality.offset_scaled_log_variance);
420 msg->announce.steps_rm = ntohs(msg->announce.steps_rm);
421 break;
422 case PTP_MSG_SIGNALING:
423 msg_port_id_post_recv(&msg->signaling.target_port_id);
424 break;
425 case PTP_MSG_MANAGEMENT:
426 msg_port_id_post_recv(&msg->management.target_port_id);
427 break;
428 }
429
430 tlv_len = msg_tlv_post_recv(msg, cnt - msg_size[type]);
431 if (tlv_len < 0) {
432 LOG_ERR("Failed processing TLVs");
433 return -EBADMSG;
434 }
435
436 if (msg_size[type] + tlv_len != msg->header.msg_length) {
437 LOG_ERR("Length and TLVs don't correspond with specified in the message");
438 return -EMSGSIZE;
439 }
440
441 return 0;
442 }
443
ptp_msg_add_tlv(struct ptp_msg * msg,int length)444 struct ptp_tlv *ptp_msg_add_tlv(struct ptp_msg *msg, int length)
445 {
446 struct ptp_tlv_container *tlv_container;
447 uint8_t *suffix = msg_suffix(msg);
448
449 if (!suffix) {
450 return NULL;
451 }
452
453 tlv_container = (struct ptp_tlv_container *)sys_slist_peek_tail(&msg->tlvs);
454 if (tlv_container) {
455 suffix = (uint8_t *)tlv_container->tlv;
456 suffix += sizeof(*tlv_container->tlv);
457 suffix += tlv_container->tlv->length;
458 }
459
460 if ((intptr_t)(suffix + length) >= (intptr_t)&msg->ref) {
461 LOG_ERR("Not enough space for TLV of %d length", length);
462 return NULL;
463 }
464
465 tlv_container = ptp_tlv_alloc();
466 if (tlv_container) {
467 tlv_container->tlv = (struct ptp_tlv *)suffix;
468 msg->header.msg_length += length;
469 }
470
471 return tlv_container ? tlv_container->tlv : NULL;
472 }
473
ptp_msg_announce_cmp(const struct ptp_announce_msg * m1,const struct ptp_announce_msg * m2)474 int ptp_msg_announce_cmp(const struct ptp_announce_msg *m1, const struct ptp_announce_msg *m2)
475 {
476 int len = sizeof(m1->gm_priority1) + sizeof(m1->gm_clk_quality) +
477 sizeof(m1->gm_priority1) + sizeof(m1->gm_id) +
478 sizeof(m1->steps_rm);
479
480 return memcmp(&m1->gm_priority1, &m2->gm_priority1, len);
481 }
482
ptp_msg_current_parent(const struct ptp_msg * msg)483 bool ptp_msg_current_parent(const struct ptp_msg *msg)
484 {
485 const struct ptp_parent_ds *pds = ptp_clock_parent_ds();
486
487 return ptp_port_id_eq(&pds->port_id, &msg->header.src_port_id);
488 }
489