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, 4);
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 = net_ntohs(ts->seconds_high);
55 	msg->timestamp.protocol._sec.low = net_ntohl(ts->seconds_low);
56 	msg->timestamp.protocol.nanosecond = net_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 = net_htons(ts->seconds_high);
62 	ts->seconds_low = net_htonl(ts->seconds_low);
63 	ts->nanoseconds = net_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 = net_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 = net_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 = net_ntohs(header->msg_length);
84 	header->correction = net_ntohll(header->correction);
85 	header->sequence_id = net_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 = net_htons(header->msg_length);
95 	header->correction = net_htonll(header->correction);
96 	header->sequence_id = net_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 = net_ntohs(tlv_container->tlv->type);
160 		tlv_container->tlv->length = net_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 		buf->frags = NULL;
279 
280 		hdr = net_udp_get_hdr(pkt, NULL);
281 
282 		/* insert back temporarily femoved frag. */
283 		net_pkt_frag_insert(pkt, buf);
284 	} else {
285 		hdr = net_udp_get_hdr(pkt, NULL);
286 	}
287 
288 	if (!hdr) {
289 		LOG_ERR("Couldn't retrieve UDP header from the net packet");
290 		return NULL;
291 	}
292 
293 	payload = net_ntohs(hdr->len) - NET_UDPH_LEN;
294 	port = net_ntohs(hdr->dst_port);
295 
296 	if (port != PTP_SOCKET_PORT_EVENT && port != PTP_SOCKET_PORT_GENERAL) {
297 		LOG_ERR("Couldn't retrieve PTP message from the net packet");
298 		return NULL;
299 	}
300 
301 	msg = (struct ptp_msg *)((uintptr_t)hdr + NET_UDPH_LEN);
302 
303 	if (payload == net_ntohs(msg->header.msg_length)) {
304 		return msg;
305 	}
306 
307 	return NULL;
308 }
309 
ptp_msg_pre_send(struct ptp_msg * msg)310 void ptp_msg_pre_send(struct ptp_msg *msg)
311 {
312 	int64_t current;
313 
314 	msg_header_pre_send(&msg->header);
315 
316 	switch (ptp_msg_type(msg)) {
317 	case PTP_MSG_SYNC:
318 		break;
319 	case PTP_MSG_DELAY_REQ:
320 		current = k_uptime_get();
321 
322 		msg->timestamp.host.second = (uint64_t)(current / MSEC_PER_SEC);
323 		msg->timestamp.host.nanosecond = (current % MSEC_PER_SEC) * NSEC_PER_MSEC;
324 		break;
325 	case PTP_MSG_PDELAY_REQ:
326 		break;
327 	case PTP_MSG_PDELAY_RESP:
328 		msg_timestamp_pre_send(&msg->pdelay_resp.req_receipt_timestamp);
329 		msg_port_id_pre_send(&msg->pdelay_resp.req_port_id);
330 		break;
331 	case PTP_MSG_FOLLOW_UP:
332 		msg_timestamp_pre_send(&msg->follow_up.precise_origin_timestamp);
333 		break;
334 	case PTP_MSG_DELAY_RESP:
335 		msg_timestamp_pre_send(&msg->delay_resp.receive_timestamp);
336 		msg_port_id_pre_send(&msg->delay_resp.req_port_id);
337 		break;
338 	case PTP_MSG_PDELAY_RESP_FOLLOW_UP:
339 		msg_timestamp_pre_send(&msg->pdelay_resp_follow_up.resp_origin_timestamp);
340 		msg_port_id_pre_send(&msg->pdelay_resp_follow_up.req_port_id);
341 		break;
342 	case PTP_MSG_ANNOUNCE:
343 		msg->announce.current_utc_offset = net_htons(msg->announce.current_utc_offset);
344 		msg->announce.gm_clk_quality.offset_scaled_log_variance =
345 			net_htons(msg->announce.gm_clk_quality.offset_scaled_log_variance);
346 		msg->announce.steps_rm = net_htons(msg->announce.steps_rm);
347 		break;
348 	case PTP_MSG_SIGNALING:
349 		msg_port_id_pre_send(&msg->signaling.target_port_id);
350 		break;
351 	case PTP_MSG_MANAGEMENT:
352 		msg_port_id_pre_send(&msg->management.target_port_id);
353 		break;
354 	}
355 
356 	msg_tlv_pre_send(msg);
357 }
358 
ptp_msg_post_recv(struct ptp_port * port,struct ptp_msg * msg,int cnt)359 int ptp_msg_post_recv(struct ptp_port *port, struct ptp_msg *msg, int cnt)
360 {
361 	static const int msg_size[] = {
362 		[PTP_MSG_SYNC]		        = sizeof(struct ptp_sync_msg),
363 		[PTP_MSG_DELAY_REQ]	        = sizeof(struct ptp_delay_req_msg),
364 		[PTP_MSG_PDELAY_REQ]	        = sizeof(struct ptp_pdelay_req_msg),
365 		[PTP_MSG_PDELAY_RESP]	        = sizeof(struct ptp_pdelay_resp_msg),
366 		[PTP_MSG_FOLLOW_UP]	        = sizeof(struct ptp_follow_up_msg),
367 		[PTP_MSG_DELAY_RESP]	        = sizeof(struct ptp_delay_resp_msg),
368 		[PTP_MSG_PDELAY_RESP_FOLLOW_UP] = sizeof(struct ptp_pdelay_resp_follow_up_msg),
369 		[PTP_MSG_ANNOUNCE]	        = sizeof(struct ptp_announce_msg),
370 		[PTP_MSG_SIGNALING]	        = sizeof(struct ptp_signaling_msg),
371 		[PTP_MSG_MANAGEMENT]	        = sizeof(struct ptp_management_msg),
372 	};
373 	enum ptp_msg_type type = ptp_msg_type(msg);
374 	int64_t current;
375 	int tlv_len;
376 
377 	if (msg_size[type] > cnt) {
378 		LOG_ERR("Received message with incorrect length");
379 		return -EBADMSG;
380 	}
381 
382 	if (msg_header_post_recv(&msg->header)) {
383 		LOG_ERR("Received message incomplient with supported PTP version");
384 		return -EBADMSG;
385 	}
386 
387 	LOG_DBG("Port %d received %s message", port->port_ds.id.port_number, msg_type_str(msg));
388 
389 	switch (type) {
390 	case PTP_MSG_SYNC:
391 		msg_timestamp_post_recv(msg, &msg->sync.origin_timestamp);
392 		break;
393 	case PTP_MSG_DELAY_REQ:
394 		break;
395 	case PTP_MSG_PDELAY_REQ:
396 		break;
397 	case PTP_MSG_PDELAY_RESP:
398 		msg_timestamp_post_recv(msg, &msg->pdelay_resp.req_receipt_timestamp);
399 		msg_port_id_post_recv(&msg->pdelay_resp.req_port_id);
400 		break;
401 	case PTP_MSG_FOLLOW_UP:
402 		msg_timestamp_post_recv(msg, &msg->follow_up.precise_origin_timestamp);
403 		break;
404 	case PTP_MSG_DELAY_RESP:
405 		msg_timestamp_post_recv(msg, &msg->delay_resp.receive_timestamp);
406 		msg_port_id_post_recv(&msg->delay_resp.req_port_id);
407 		break;
408 	case PTP_MSG_PDELAY_RESP_FOLLOW_UP:
409 		msg_timestamp_post_recv(msg, &msg->pdelay_resp_follow_up.resp_origin_timestamp);
410 		msg_port_id_post_recv(&msg->pdelay_resp_follow_up.req_port_id);
411 		break;
412 	case PTP_MSG_ANNOUNCE:
413 		current = k_uptime_get();
414 
415 		msg->timestamp.host.second = (uint64_t)(current / MSEC_PER_SEC);
416 		msg->timestamp.host.nanosecond = (current % MSEC_PER_SEC) * NSEC_PER_MSEC;
417 		msg_timestamp_post_recv(msg, &msg->announce.origin_timestamp);
418 		msg->announce.current_utc_offset = net_ntohs(msg->announce.current_utc_offset);
419 		msg->announce.gm_clk_quality.offset_scaled_log_variance =
420 			net_ntohs(msg->announce.gm_clk_quality.offset_scaled_log_variance);
421 		msg->announce.steps_rm = net_ntohs(msg->announce.steps_rm);
422 		break;
423 	case PTP_MSG_SIGNALING:
424 		msg_port_id_post_recv(&msg->signaling.target_port_id);
425 		break;
426 	case PTP_MSG_MANAGEMENT:
427 		msg_port_id_post_recv(&msg->management.target_port_id);
428 		break;
429 	}
430 
431 	tlv_len = msg_tlv_post_recv(msg, cnt - msg_size[type]);
432 	if (tlv_len < 0) {
433 		LOG_ERR("Failed processing TLVs");
434 		return -EBADMSG;
435 	}
436 
437 	if (msg_size[type] + tlv_len != msg->header.msg_length) {
438 		LOG_ERR("Length and TLVs don't correspond with specified in the message");
439 		return -EMSGSIZE;
440 	}
441 
442 	return 0;
443 }
444 
ptp_msg_add_tlv(struct ptp_msg * msg,int length)445 struct ptp_tlv *ptp_msg_add_tlv(struct ptp_msg *msg, int length)
446 {
447 	struct ptp_tlv_container *tlv_container;
448 	uint8_t *suffix = msg_suffix(msg);
449 
450 	if (!suffix) {
451 		return NULL;
452 	}
453 
454 	tlv_container = (struct ptp_tlv_container *)sys_slist_peek_tail(&msg->tlvs);
455 	if (tlv_container) {
456 		suffix = (uint8_t *)tlv_container->tlv;
457 		suffix += sizeof(*tlv_container->tlv);
458 		suffix += tlv_container->tlv->length;
459 	}
460 
461 	if ((intptr_t)(suffix + length) >= (intptr_t)&msg->ref) {
462 		LOG_ERR("Not enough space for TLV of %d length", length);
463 		return NULL;
464 	}
465 
466 	tlv_container = ptp_tlv_alloc();
467 	if (tlv_container) {
468 		tlv_container->tlv = (struct ptp_tlv *)suffix;
469 		msg->header.msg_length += length;
470 	}
471 
472 	return tlv_container ? tlv_container->tlv : NULL;
473 }
474 
ptp_msg_announce_cmp(const struct ptp_announce_msg * m1,const struct ptp_announce_msg * m2)475 int ptp_msg_announce_cmp(const struct ptp_announce_msg *m1, const struct ptp_announce_msg *m2)
476 {
477 	int len = sizeof(m1->gm_priority1) + sizeof(m1->gm_clk_quality) +
478 		  sizeof(m1->gm_priority1) + sizeof(m1->gm_id) +
479 		  sizeof(m1->steps_rm);
480 
481 	return memcmp(&m1->gm_priority1, &m2->gm_priority1, len);
482 }
483 
ptp_msg_current_parent(const struct ptp_msg * msg)484 bool ptp_msg_current_parent(const struct ptp_msg *msg)
485 {
486 	const struct ptp_parent_ds *pds = ptp_clock_parent_ds();
487 
488 	return ptp_port_id_eq(&pds->port_id, &msg->header.src_port_id);
489 }
490