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_tlv, CONFIG_PTP_LOG_LEVEL);
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/net/net_ip.h>
12 
13 #include "port.h"
14 #include "tlv.h"
15 
16 #define TLV_MANUFACTURER_ID_LEN (3)
17 #define TLV_PROFILE_ID_LEN (6)
18 #define TLV_ADDR_LEN_MAX (16)
19 
20 K_MEM_SLAB_DEFINE_STATIC(tlv_slab,
21 			 sizeof(struct ptp_tlv_container),
22 			 2 * CONFIG_PTP_MSG_POLL_SIZE,
23 			 8);
24 
tlv_ntohs(void * ptr)25 static inline void tlv_ntohs(void *ptr)
26 {
27 	uint16_t val = *(uint16_t *)ptr;
28 
29 	val = ntohs(val);
30 	memcpy(ptr, &val, sizeof(val));
31 }
32 
tlv_htons(void * ptr)33 static inline void tlv_htons(void *ptr)
34 {
35 	uint16_t val = *(uint16_t *)ptr;
36 
37 	val = htons(val);
38 	memcpy(ptr, &val, sizeof(val));
39 }
40 
tlv_mgmt_post_recv(struct ptp_tlv_mgmt * mgmt_tlv,uint16_t length)41 static int tlv_mgmt_post_recv(struct ptp_tlv_mgmt *mgmt_tlv, uint16_t length)
42 {
43 	struct ptp_tlv_mgmt_clock_desc *clock_desc;
44 	struct ptp_tlv_time_prop_ds *time_prop_ds;
45 	struct ptp_tlv_default_ds *default_ds;
46 	struct ptp_tlv_current_ds *current_ds;
47 	struct ptp_tlv_parent_ds *parent_ds;
48 	struct ptp_tlv_port_ds *port_ds;
49 	struct ptp_timestamp ts;
50 
51 	enum ptp_mgmt_id id = (enum ptp_mgmt_id)mgmt_tlv->id;
52 	struct ptp_tlv_container *container;
53 	uint8_t *data;
54 	int32_t data_length;
55 
56 	switch (id) {
57 	case PTP_MGMT_NULL_PTP_MANAGEMENT:
58 		__fallthrough;
59 	case PTP_MGMT_SAVE_IN_NON_VOLATILE_STORAGE:
60 		__fallthrough;
61 	case PTP_MGMT_RESET_NON_VOLATILE_STORAGE:
62 		__fallthrough;
63 	case PTP_MGMT_FAULT_LOG_RESET:
64 		__fallthrough;
65 	case PTP_MGMT_ENABLE_PORT:
66 		__fallthrough;
67 	case PTP_MGMT_DISABLE_PORT:
68 		if (length != 0) {
69 			return -EBADMSG;
70 		}
71 		break;
72 	case PTP_MGMT_CLOCK_DESCRIPTION:
73 		container = CONTAINER_OF((void *)mgmt_tlv, struct ptp_tlv_container, tlv);
74 
75 		clock_desc = &container->clock_desc;
76 		data = mgmt_tlv->data;
77 		data_length = length;
78 
79 		clock_desc->type = (uint16_t *)data;
80 		data += sizeof(*clock_desc->type);
81 		data_length -= sizeof(*clock_desc->type);
82 		if (data_length < 0) {
83 			return -EBADMSG;
84 		}
85 		tlv_ntohs(&clock_desc->type);
86 
87 		clock_desc->phy_protocol = (struct ptp_text *)data;
88 		data += sizeof(*clock_desc->phy_protocol);
89 		data_length -= sizeof(*clock_desc->phy_protocol);
90 		if (data_length < 0) {
91 			return -EBADMSG;
92 		}
93 		data += clock_desc->phy_protocol->length;
94 		data_length -= clock_desc->phy_protocol->length;
95 		if (data_length < 0) {
96 			return -EBADMSG;
97 		}
98 
99 		clock_desc->phy_addr_len = (uint16_t *)data;
100 		data += sizeof(*clock_desc->phy_addr_len);
101 		data_length -= sizeof(*clock_desc->phy_addr_len);
102 		if (data_length < 0) {
103 			return -EBADMSG;
104 		}
105 		tlv_ntohs(&clock_desc->phy_addr_len);
106 		if (*clock_desc->phy_addr_len > TLV_ADDR_LEN_MAX) {
107 			return -EBADMSG;
108 		}
109 
110 		clock_desc->phy_addr = data;
111 		data += *clock_desc->phy_addr_len;
112 		data_length -= *clock_desc->phy_addr_len;
113 		if (data_length < 0) {
114 			return -EBADMSG;
115 		}
116 
117 		clock_desc->protocol_addr = (struct ptp_port_addr *)data;
118 		data += sizeof(*clock_desc->protocol_addr);
119 		data_length -= sizeof(*clock_desc->protocol_addr);
120 		if (data_length < 0) {
121 			return -EBADMSG;
122 		}
123 		tlv_ntohs(&clock_desc->protocol_addr->protocol);
124 		tlv_ntohs(&clock_desc->protocol_addr->addr_len);
125 		if (clock_desc->protocol_addr->addr_len > TLV_ADDR_LEN_MAX) {
126 			return -EBADMSG;
127 		}
128 
129 		data += clock_desc->protocol_addr->addr_len;
130 		data_length -= clock_desc->protocol_addr->addr_len;
131 		if (data_length < 0) {
132 			return -EBADMSG;
133 		}
134 
135 		clock_desc->manufacturer_id = data;
136 		/* extra byte for reserved field - see IEEE 1588-2019 15.5.3.1.2 */
137 		data += TLV_MANUFACTURER_ID_LEN + 1;
138 		data_length -= TLV_MANUFACTURER_ID_LEN + 1;
139 		if (data_length < 0) {
140 			return -EBADMSG;
141 		}
142 
143 		clock_desc->product_desc = (struct ptp_text *)data;
144 		data += sizeof(*clock_desc->product_desc);
145 		data_length -= sizeof(*clock_desc->product_desc);
146 		if (data_length < 0) {
147 			return -EBADMSG;
148 		}
149 		data += clock_desc->product_desc->length;
150 		data_length -= clock_desc->product_desc->length;
151 		if (data_length < 0) {
152 			return -EBADMSG;
153 		}
154 
155 		clock_desc->revision_data = (struct ptp_text *)data;
156 		data += sizeof(*clock_desc->revision_data);
157 		data_length -= sizeof(*clock_desc->revision_data);
158 		if (data_length < 0) {
159 			return -EBADMSG;
160 		}
161 		data += clock_desc->revision_data->length;
162 		data_length -= clock_desc->revision_data->length;
163 		if (data_length < 0) {
164 			return -EBADMSG;
165 		}
166 
167 		clock_desc->user_desc = (struct ptp_text *)data;
168 		data += sizeof(*clock_desc->user_desc);
169 		data_length -= sizeof(*clock_desc->user_desc);
170 		if (data_length < 0) {
171 			return -EBADMSG;
172 		}
173 		data += clock_desc->user_desc->length;
174 		data_length -= clock_desc->user_desc->length;
175 		if (data_length < 0) {
176 			return -EBADMSG;
177 		}
178 
179 		clock_desc->profile_id = data;
180 		data += TLV_PROFILE_ID_LEN;
181 		data_length -= TLV_PROFILE_ID_LEN;
182 
183 		break;
184 	case PTP_MGMT_USER_DESCRIPTION:
185 		container = CONTAINER_OF((void *)mgmt_tlv, struct ptp_tlv_container, tlv);
186 
187 		if (length < sizeof(struct ptp_text)) {
188 			return -EBADMSG;
189 		}
190 		container->clock_desc.user_desc = (struct ptp_text *)mgmt_tlv->data;
191 		break;
192 	case PTP_MGMT_DEFAULT_DATA_SET:
193 		if (length != sizeof(struct ptp_tlv_default_ds)) {
194 			return -EBADMSG;
195 		}
196 		default_ds = (struct ptp_tlv_default_ds *)mgmt_tlv->data;
197 
198 		default_ds->n_ports = ntohs(default_ds->n_ports);
199 		default_ds->clk_quality.offset_scaled_log_variance =
200 			ntohs(default_ds->clk_quality.offset_scaled_log_variance);
201 		break;
202 	case PTP_MGMT_CURRENT_DATA_SET:
203 		if (length != sizeof(struct ptp_tlv_current_ds)) {
204 			return -EBADMSG;
205 		}
206 		current_ds = (struct ptp_tlv_current_ds *)mgmt_tlv->data;
207 
208 		current_ds->steps_rm = ntohs(current_ds->steps_rm);
209 		current_ds->offset_from_tt = ntohll(current_ds->offset_from_tt);
210 		current_ds->mean_delay = ntohll(current_ds->mean_delay);
211 		break;
212 	case PTP_MGMT_PARENT_DATA_SET:
213 		if (length != sizeof(struct ptp_tlv_parent_ds)) {
214 			return -EBADMSG;
215 		}
216 		parent_ds = (struct ptp_tlv_parent_ds *)mgmt_tlv->data;
217 
218 		parent_ds->port_id.port_number = ntohs(parent_ds->port_id.port_number);
219 		parent_ds->obsreved_parent_offset_scaled_log_variance =
220 			ntohs(parent_ds->obsreved_parent_offset_scaled_log_variance);
221 		parent_ds->obsreved_parent_clk_phase_change_rate =
222 			ntohl(parent_ds->obsreved_parent_clk_phase_change_rate);
223 		parent_ds->gm_clk_quality.offset_scaled_log_variance =
224 			ntohs(parent_ds->gm_clk_quality.offset_scaled_log_variance);
225 		break;
226 	case PTP_MGMT_TIME_PROPERTIES_DATA_SET:
227 		if (length != sizeof(struct ptp_tlv_time_prop_ds)) {
228 			return -EBADMSG;
229 		}
230 		time_prop_ds = (struct ptp_tlv_time_prop_ds *)mgmt_tlv->data;
231 
232 		time_prop_ds->current_utc_offset = ntohs(time_prop_ds->current_utc_offset);
233 		break;
234 	case PTP_MGMT_PORT_DATA_SET:
235 		if (length != sizeof(struct ptp_tlv_port_ds)) {
236 			return -EBADMSG;
237 		}
238 		port_ds = (struct ptp_tlv_port_ds *)mgmt_tlv->data;
239 
240 		port_ds->id.port_number = ntohs(port_ds->id.port_number);
241 		port_ds->mean_link_delay = ntohll(port_ds->mean_link_delay);
242 		break;
243 	case PTP_MGMT_TIME:
244 		ts = *(struct ptp_timestamp *)mgmt_tlv->data;
245 
246 		ts.seconds_high = ntohs(ts.seconds_high);
247 		ts.seconds_low = ntohl(ts.seconds_low);
248 		ts.nanoseconds = ntohl(ts.nanoseconds);
249 
250 		memcpy(mgmt_tlv->data, &ts, sizeof(ts));
251 		break;
252 	default:
253 		break;
254 	}
255 
256 	return 0;
257 }
258 
tlv_mgmt_pre_send(struct ptp_tlv_mgmt * mgmt_tlv)259 static void tlv_mgmt_pre_send(struct ptp_tlv_mgmt *mgmt_tlv)
260 {
261 	enum ptp_mgmt_id id = (enum ptp_mgmt_id)mgmt_tlv->id;
262 	struct ptp_tlv_mgmt_clock_desc *clock_desc;
263 	struct ptp_tlv_time_prop_ds *time_prop_ds;
264 	struct ptp_tlv_default_ds *default_ds;
265 	struct ptp_tlv_current_ds *current_ds;
266 	struct ptp_tlv_container *container;
267 	struct ptp_tlv_parent_ds *parent_ds;
268 	struct ptp_tlv_port_ds *port_ds;
269 	struct ptp_timestamp ts;
270 
271 	switch (id) {
272 	case PTP_MGMT_CLOCK_DESCRIPTION:
273 		container = CONTAINER_OF((void *)mgmt_tlv, struct ptp_tlv_container, tlv);
274 		clock_desc = &container->clock_desc;
275 
276 		tlv_htons(&clock_desc->type);
277 		tlv_htons(&clock_desc->phy_addr_len);
278 		tlv_htons(&clock_desc->protocol_addr->protocol);
279 		tlv_htons(&clock_desc->protocol_addr->addr_len);
280 		break;
281 	case PTP_MGMT_DEFAULT_DATA_SET:
282 		default_ds = (struct ptp_tlv_default_ds *)mgmt_tlv->data;
283 
284 		default_ds->n_ports = htons(default_ds->n_ports);
285 		default_ds->clk_quality.offset_scaled_log_variance =
286 			htons(default_ds->clk_quality.offset_scaled_log_variance);
287 		break;
288 	case PTP_MGMT_CURRENT_DATA_SET:
289 		current_ds = (struct ptp_tlv_current_ds *)mgmt_tlv->data;
290 
291 		current_ds->steps_rm = htons(current_ds->steps_rm);
292 		current_ds->offset_from_tt = htonll(current_ds->offset_from_tt);
293 		current_ds->mean_delay = htonll(current_ds->mean_delay);
294 		break;
295 	case PTP_MGMT_PARENT_DATA_SET:
296 		parent_ds = (struct ptp_tlv_parent_ds *)mgmt_tlv->data;
297 
298 		parent_ds->port_id.port_number = htons(parent_ds->port_id.port_number);
299 		parent_ds->obsreved_parent_offset_scaled_log_variance =
300 			htons(parent_ds->obsreved_parent_offset_scaled_log_variance);
301 		parent_ds->obsreved_parent_clk_phase_change_rate =
302 			htons(parent_ds->obsreved_parent_clk_phase_change_rate);
303 		parent_ds->gm_clk_quality.offset_scaled_log_variance =
304 			htons(parent_ds->gm_clk_quality.offset_scaled_log_variance);
305 		break;
306 	case PTP_MGMT_TIME_PROPERTIES_DATA_SET:
307 		time_prop_ds = (struct ptp_tlv_time_prop_ds *)mgmt_tlv->data;
308 
309 		time_prop_ds->current_utc_offset = htons(time_prop_ds->current_utc_offset);
310 		break;
311 	case PTP_MGMT_PORT_DATA_SET:
312 		port_ds = (struct ptp_tlv_port_ds *)mgmt_tlv->data;
313 
314 		port_ds->id.port_number = htons(port_ds->id.port_number);
315 		port_ds->mean_link_delay = htonll(port_ds->mean_link_delay);
316 		break;
317 	case PTP_MGMT_TIME:
318 		ts = *(struct ptp_timestamp *)mgmt_tlv->data;
319 
320 		ts.seconds_high = htons(ts.seconds_high);
321 		ts.seconds_low = htonl(ts.seconds_low);
322 		ts.nanoseconds = htonl(ts.nanoseconds);
323 
324 		memcpy(mgmt_tlv->data, &ts, sizeof(ts));
325 		break;
326 	default:
327 		break;
328 	}
329 }
330 
ptp_tlv_alloc(void)331 struct ptp_tlv_container *ptp_tlv_alloc(void)
332 {
333 	struct ptp_tlv_container *tlv_container = NULL;
334 	int ret = k_mem_slab_alloc(&tlv_slab, (void **)&tlv_container, K_FOREVER);
335 
336 	if (ret) {
337 		LOG_ERR("Couldn't allocate memory for the TLV");
338 		return NULL;
339 	}
340 
341 	memset(tlv_container, 0, sizeof(*tlv_container));
342 	return tlv_container;
343 }
344 
ptp_tlv_free(struct ptp_tlv_container * tlv_container)345 void ptp_tlv_free(struct ptp_tlv_container *tlv_container)
346 {
347 	k_mem_slab_free(&tlv_slab, (void *)tlv_container);
348 }
349 
ptp_mgmt_action(struct ptp_msg * msg)350 enum ptp_mgmt_op ptp_mgmt_action(struct ptp_msg *msg)
351 {
352 	return (enum ptp_mgmt_op)msg->management.action;
353 }
354 
ptp_tlv_type(struct ptp_tlv * tlv)355 enum ptp_tlv_type ptp_tlv_type(struct ptp_tlv *tlv)
356 {
357 	return (enum ptp_tlv_type)tlv->type;
358 }
359 
ptp_tlv_post_recv(struct ptp_tlv * tlv)360 int ptp_tlv_post_recv(struct ptp_tlv *tlv)
361 {
362 	struct ptp_tlv_mgmt_err *mgmt_err;
363 	struct ptp_tlv_mgmt *mgmt;
364 	int ret = 0;
365 
366 	switch (ptp_tlv_type(tlv)) {
367 	case PTP_TLV_TYPE_MANAGEMENT:
368 		if (tlv->length < (sizeof(struct ptp_tlv_mgmt) - sizeof(struct ptp_tlv))) {
369 			return -EBADMSG;
370 		}
371 		mgmt = (struct ptp_tlv_mgmt *)tlv;
372 		mgmt->id = ntohs(mgmt->id);
373 
374 		/* Value of length is 2 + N, where N is length of data field
375 		 * based on IEEE 1588-2019 Section 15.5.2.2.
376 		 */
377 		if (tlv->length > sizeof(mgmt->id)) {
378 			ret = tlv_mgmt_post_recv(mgmt, tlv->length - 2);
379 		}
380 		break;
381 	case PTP_TLV_TYPE_MANAGEMENT_ERROR_STATUS:
382 		if (tlv->length < (sizeof(struct ptp_tlv_mgmt_err) - sizeof(struct ptp_tlv))) {
383 			return -EBADMSG;
384 		}
385 		mgmt_err = (struct ptp_tlv_mgmt_err *)tlv;
386 		mgmt_err->err_id = ntohs(mgmt_err->err_id);
387 		mgmt_err->id = ntohs(mgmt_err->id);
388 		break;
389 	default:
390 		break;
391 	}
392 
393 	return ret;
394 }
395 
ptp_tlv_pre_send(struct ptp_tlv * tlv)396 void ptp_tlv_pre_send(struct ptp_tlv *tlv)
397 {
398 	struct ptp_tlv_mgmt_err *mgmt_err;
399 	struct ptp_tlv_mgmt *mgmt;
400 
401 	switch (ptp_tlv_type(tlv)) {
402 	case PTP_TLV_TYPE_MANAGEMENT:
403 		mgmt = (struct ptp_tlv_mgmt *)tlv;
404 
405 		/* Check if management TLV contains data */
406 		if (tlv->length > sizeof(mgmt->id)) {
407 			tlv_mgmt_pre_send(mgmt);
408 		}
409 		mgmt->id = htons(mgmt->id);
410 		break;
411 	case PTP_TLV_TYPE_MANAGEMENT_ERROR_STATUS:
412 		mgmt_err = (struct ptp_tlv_mgmt_err *)tlv;
413 
414 		mgmt_err->err_id = htons(mgmt_err->err_id);
415 		mgmt_err->id = htons(mgmt_err->id);
416 		break;
417 	default:
418 		break;
419 	}
420 
421 	tlv->length = htons(tlv->length);
422 	tlv->type = htons(tlv->type);
423 }
424