1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  *
10  * Ethernet driver for native posix board. This is meant for network
11  * connectivity between host and Zephyr.
12  */
13 
14 #define LOG_MODULE_NAME eth_posix
15 #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
19 
20 #include <stdio.h>
21 
22 #include <zephyr/kernel.h>
23 #include <stdbool.h>
24 #include <errno.h>
25 #include <stddef.h>
26 
27 #include <zephyr/net/net_pkt.h>
28 #include <zephyr/net/net_core.h>
29 #include <zephyr/net/net_if.h>
30 #include <zephyr/net/ethernet.h>
31 #include <ethernet/eth_stats.h>
32 
33 #include <zephyr/drivers/ptp_clock.h>
34 #include <zephyr/net/gptp.h>
35 #include <zephyr/net/lldp.h>
36 
37 #include "eth_native_posix_priv.h"
38 #include "nsi_host_trampolines.h"
39 #include "eth.h"
40 
41 #define NET_BUF_TIMEOUT K_MSEC(100)
42 
43 #if defined(CONFIG_NET_VLAN)
44 #define ETH_HDR_LEN sizeof(struct net_eth_vlan_hdr)
45 #else
46 #define ETH_HDR_LEN sizeof(struct net_eth_hdr)
47 #endif
48 
49 struct eth_context {
50 	uint8_t recv[NET_ETH_MTU + ETH_HDR_LEN];
51 	uint8_t send[NET_ETH_MTU + ETH_HDR_LEN];
52 	uint8_t mac_addr[6];
53 	struct net_linkaddr ll_addr;
54 	struct net_if *iface;
55 	const char *if_name;
56 	k_tid_t rx_thread;
57 	struct z_thread_stack_element *rx_stack;
58 	size_t rx_stack_size;
59 	int dev_fd;
60 	bool init_done;
61 	bool status;
62 	bool promisc_mode;
63 
64 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
65 	struct net_stats_eth stats;
66 #endif
67 #if defined(CONFIG_ETH_NATIVE_POSIX_PTP_CLOCK)
68 	const struct device *ptp_clock;
69 #endif
70 };
71 
72 #define DEFINE_RX_THREAD(x, _)						\
73 	K_KERNEL_STACK_DEFINE(rx_thread_stack_##x,			\
74 			      CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE);\
75 	static struct k_thread rx_thread_data_##x
76 
77 LISTIFY(CONFIG_ETH_NATIVE_POSIX_INTERFACE_COUNT, DEFINE_RX_THREAD, (;), _);
78 
79 #if defined(CONFIG_NET_GPTP)
need_timestamping(struct gptp_hdr * hdr)80 static bool need_timestamping(struct gptp_hdr *hdr)
81 {
82 	switch (hdr->message_type) {
83 	case GPTP_SYNC_MESSAGE:
84 	case GPTP_PATH_DELAY_RESP_MESSAGE:
85 		return true;
86 	default:
87 		return false;
88 	}
89 }
90 
check_gptp_msg(struct net_if * iface,struct net_pkt * pkt,bool is_tx)91 static struct gptp_hdr *check_gptp_msg(struct net_if *iface,
92 				       struct net_pkt *pkt,
93 				       bool is_tx)
94 {
95 	uint8_t *msg_start = net_pkt_data(pkt);
96 	struct gptp_hdr *gptp_hdr;
97 	int eth_hlen;
98 
99 #if defined(CONFIG_NET_VLAN)
100 	if (net_eth_get_vlan_status(iface)) {
101 		struct net_eth_vlan_hdr *hdr_vlan;
102 
103 		hdr_vlan = (struct net_eth_vlan_hdr *)msg_start;
104 		if (ntohs(hdr_vlan->type) != NET_ETH_PTYPE_PTP) {
105 			return NULL;
106 		}
107 
108 		eth_hlen = sizeof(struct net_eth_vlan_hdr);
109 	} else
110 #endif
111 	{
112 		struct net_eth_hdr *hdr;
113 
114 		hdr = (struct net_eth_hdr *)msg_start;
115 		if (ntohs(hdr->type) != NET_ETH_PTYPE_PTP) {
116 			return NULL;
117 		}
118 
119 
120 		eth_hlen = sizeof(struct net_eth_hdr);
121 	}
122 
123 	/* In TX, the first net_buf contains the Ethernet header
124 	 * and the actual gPTP header is in the second net_buf.
125 	 * In RX, the Ethernet header + other headers are in the
126 	 * first net_buf.
127 	 */
128 	if (is_tx) {
129 		if (pkt->frags->frags == NULL) {
130 			return false;
131 		}
132 
133 		gptp_hdr = (struct gptp_hdr *)pkt->frags->frags->data;
134 	} else {
135 		gptp_hdr = (struct gptp_hdr *)(pkt->frags->data + eth_hlen);
136 	}
137 
138 	return gptp_hdr;
139 }
140 
update_pkt_priority(struct gptp_hdr * hdr,struct net_pkt * pkt)141 static void update_pkt_priority(struct gptp_hdr *hdr, struct net_pkt *pkt)
142 {
143 	if (GPTP_IS_EVENT_MSG(hdr->message_type)) {
144 		net_pkt_set_priority(pkt, NET_PRIORITY_CA);
145 	} else {
146 		net_pkt_set_priority(pkt, NET_PRIORITY_IC);
147 	}
148 }
149 
update_gptp(struct net_if * iface,struct net_pkt * pkt,bool send)150 static void update_gptp(struct net_if *iface, struct net_pkt *pkt,
151 			bool send)
152 {
153 	struct net_ptp_time timestamp;
154 	struct gptp_hdr *hdr;
155 	int ret;
156 
157 	ret = eth_clock_gettime(&timestamp.second, &timestamp.nanosecond);
158 	if (ret < 0) {
159 		return;
160 	}
161 
162 	net_pkt_set_timestamp(pkt, &timestamp);
163 
164 	hdr = check_gptp_msg(iface, pkt, send);
165 	if (!hdr) {
166 		return;
167 	}
168 
169 	if (send) {
170 		ret = need_timestamping(hdr);
171 		if (ret) {
172 			net_if_add_tx_timestamp(pkt);
173 		}
174 	} else {
175 		update_pkt_priority(hdr, pkt);
176 	}
177 }
178 #else
179 #define update_gptp(iface, pkt, send)
180 #endif /* CONFIG_NET_GPTP */
181 
eth_send(const struct device * dev,struct net_pkt * pkt)182 static int eth_send(const struct device *dev, struct net_pkt *pkt)
183 {
184 	struct eth_context *ctx = dev->data;
185 	int count = net_pkt_get_len(pkt);
186 	int ret;
187 
188 	ret = net_pkt_read(pkt, ctx->send, count);
189 	if (ret) {
190 		return ret;
191 	}
192 
193 	update_gptp(net_pkt_iface(pkt), pkt, true);
194 
195 	LOG_DBG("Send pkt %p len %d", pkt, count);
196 
197 	ret = nsi_host_write(ctx->dev_fd, ctx->send, count);
198 	if (ret < 0) {
199 		LOG_DBG("Cannot send pkt %p (%d)", pkt, ret);
200 	}
201 
202 	return ret < 0 ? ret : 0;
203 }
204 
eth_get_mac(struct eth_context * ctx)205 static struct net_linkaddr *eth_get_mac(struct eth_context *ctx)
206 {
207 	ctx->ll_addr.addr = ctx->mac_addr;
208 	ctx->ll_addr.len = sizeof(ctx->mac_addr);
209 
210 	return &ctx->ll_addr;
211 }
212 
get_iface(struct eth_context * ctx,uint16_t vlan_tag)213 static inline struct net_if *get_iface(struct eth_context *ctx,
214 				       uint16_t vlan_tag)
215 {
216 #if defined(CONFIG_NET_VLAN)
217 	struct net_if *iface;
218 
219 	iface = net_eth_get_vlan_iface(ctx->iface, vlan_tag);
220 	if (!iface) {
221 		return ctx->iface;
222 	}
223 
224 	return iface;
225 #else
226 	ARG_UNUSED(vlan_tag);
227 
228 	return ctx->iface;
229 #endif
230 }
231 
232 #if defined(CONFIG_NET_VLAN)
prepare_vlan_pkt(struct eth_context * ctx,int count,uint16_t * vlan_tag,int * status)233 static struct net_pkt *prepare_vlan_pkt(struct eth_context *ctx,
234 					int count, uint16_t *vlan_tag, int *status)
235 {
236 	struct net_eth_vlan_hdr *hdr = (struct net_eth_vlan_hdr *)ctx->recv;
237 	struct net_pkt *pkt;
238 	uint8_t pos;
239 
240 	if (IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_VLAN_TAG_STRIP)) {
241 		count -= NET_ETH_VLAN_HDR_SIZE;
242 	}
243 
244 	pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, count,
245 					   AF_UNSPEC, 0, NET_BUF_TIMEOUT);
246 	if (!pkt) {
247 		*status = -ENOMEM;
248 		return NULL;
249 	}
250 
251 	net_pkt_set_vlan_tci(pkt, ntohs(hdr->vlan.tci));
252 	*vlan_tag = net_pkt_vlan_tag(pkt);
253 
254 	pos = 0;
255 
256 	if (IS_ENABLED(CONFIG_ETH_NATIVE_POSIX_VLAN_TAG_STRIP)) {
257 		if (net_pkt_write(pkt, ctx->recv,
258 				  2 * sizeof(struct net_eth_addr))) {
259 			goto error;
260 		}
261 
262 		pos = (2 * sizeof(struct net_eth_addr)) + NET_ETH_VLAN_HDR_SIZE;
263 		count -= (2 * sizeof(struct net_eth_addr));
264 	}
265 
266 	if (net_pkt_write(pkt, ctx->recv + pos, count)) {
267 		goto error;
268 	}
269 
270 #if CONFIG_NET_TC_RX_COUNT > 1
271 	{
272 		enum net_priority prio;
273 
274 		prio = net_vlan2priority(net_pkt_vlan_priority(pkt));
275 		net_pkt_set_priority(pkt, prio);
276 	}
277 #endif
278 
279 	*status = 0;
280 
281 	LOG_DBG("Recv pkt %p len %d", pkt, count);
282 
283 	return pkt;
284 
285 error:
286 	net_pkt_unref(pkt);
287 	*status = -ENOBUFS;
288 	return NULL;
289 }
290 #endif
291 
prepare_non_vlan_pkt(struct eth_context * ctx,int count,int * status)292 static struct net_pkt *prepare_non_vlan_pkt(struct eth_context *ctx,
293 					    int count, int *status)
294 {
295 	struct net_pkt *pkt;
296 
297 	pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, count,
298 					   AF_UNSPEC, 0, NET_BUF_TIMEOUT);
299 	if (!pkt) {
300 		*status = -ENOMEM;
301 		return NULL;
302 	}
303 
304 	if (net_pkt_write(pkt, ctx->recv, count)) {
305 		net_pkt_unref(pkt);
306 		*status = -ENOBUFS;
307 		return NULL;
308 	}
309 
310 	*status = 0;
311 
312 	LOG_DBG("Recv pkt %p len %d", pkt, count);
313 
314 	return pkt;
315 }
316 
read_data(struct eth_context * ctx,int fd)317 static int read_data(struct eth_context *ctx, int fd)
318 {
319 	uint16_t vlan_tag = NET_VLAN_TAG_UNSPEC;
320 	struct net_if *iface;
321 	struct net_pkt *pkt = NULL;
322 	int status;
323 	int count;
324 
325 	count = nsi_host_read(fd, ctx->recv, sizeof(ctx->recv));
326 	if (count <= 0) {
327 		return 0;
328 	}
329 
330 #if defined(CONFIG_NET_VLAN)
331 	{
332 		struct net_eth_hdr *hdr = (struct net_eth_hdr *)(ctx->recv);
333 
334 		if (ntohs(hdr->type) == NET_ETH_PTYPE_VLAN) {
335 			pkt = prepare_vlan_pkt(ctx, count, &vlan_tag, &status);
336 			if (!pkt) {
337 				return status;
338 			}
339 		} else {
340 			pkt = prepare_non_vlan_pkt(ctx, count, &status);
341 			if (!pkt) {
342 				return status;
343 			}
344 
345 			net_pkt_set_vlan_tci(pkt, 0);
346 		}
347 	}
348 #else
349 	{
350 		pkt = prepare_non_vlan_pkt(ctx, count, &status);
351 		if (!pkt) {
352 			return status;
353 		}
354 	}
355 #endif
356 
357 	iface = get_iface(ctx, vlan_tag);
358 
359 	update_gptp(iface, pkt, false);
360 
361 	if (net_recv_data(iface, pkt) < 0) {
362 		net_pkt_unref(pkt);
363 	}
364 
365 	return 0;
366 }
367 
eth_rx(void * p1,void * p2,void * p3)368 static void eth_rx(void *p1, void *p2, void *p3)
369 {
370 	ARG_UNUSED(p2);
371 	ARG_UNUSED(p3);
372 
373 	struct eth_context *ctx = p1;
374 	LOG_DBG("Starting ZETH RX thread");
375 
376 	while (1) {
377 		if (net_if_is_up(ctx->iface)) {
378 			while (!eth_wait_data(ctx->dev_fd)) {
379 				read_data(ctx, ctx->dev_fd);
380 				k_yield();
381 			}
382 		}
383 
384 		k_sleep(K_MSEC(CONFIG_ETH_NATIVE_POSIX_RX_TIMEOUT));
385 	}
386 }
387 
388 #if defined(CONFIG_THREAD_MAX_NAME_LEN)
389 #define THREAD_MAX_NAME_LEN CONFIG_THREAD_MAX_NAME_LEN
390 #else
391 #define THREAD_MAX_NAME_LEN 1
392 #endif
393 
create_rx_handler(struct eth_context * ctx)394 static void create_rx_handler(struct eth_context *ctx)
395 {
396 	k_thread_create(ctx->rx_thread,
397 			ctx->rx_stack,
398 			ctx->rx_stack_size,
399 			eth_rx,
400 			ctx, NULL, NULL, K_PRIO_COOP(14),
401 			0, K_NO_WAIT);
402 
403 	if (IS_ENABLED(CONFIG_THREAD_NAME)) {
404 		char name[THREAD_MAX_NAME_LEN];
405 
406 		snprintk(name, sizeof(name), "eth_native_posix_rx-%s",
407 			 ctx->if_name);
408 		k_thread_name_set(ctx->rx_thread, name);
409 	}
410 }
411 
eth_iface_init(struct net_if * iface)412 static void eth_iface_init(struct net_if *iface)
413 {
414 	struct eth_context *ctx = net_if_get_device(iface)->data;
415 	struct net_linkaddr *ll_addr = eth_get_mac(ctx);
416 
417 	/* The iface pointer in context should contain the main interface
418 	 * if the VLANs are enabled.
419 	 */
420 	if (ctx->iface == NULL) {
421 		ctx->iface = iface;
422 	}
423 
424 	ethernet_init(iface);
425 
426 	if (ctx->init_done) {
427 		return;
428 	}
429 
430 	net_lldp_set_lldpdu(iface);
431 
432 	ctx->init_done = true;
433 
434 #if defined(CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC)
435 	/* 00-00-5E-00-53-xx Documentation RFC 7042 */
436 	gen_random_mac(ctx->mac_addr, 0x00, 0x00, 0x5E);
437 
438 	ctx->mac_addr[3] = 0x00;
439 	ctx->mac_addr[4] = 0x53;
440 
441 	/* The TUN/TAP setup script will by default set the MAC address of host
442 	 * interface to 00:00:5E:00:53:FF so do not allow that.
443 	 */
444 	if (ctx->mac_addr[5] == 0xff) {
445 		ctx->mac_addr[5] = 0x01;
446 	}
447 #else
448 	/* Difficult to configure MAC addresses any sane way if we have more
449 	 * than one network interface.
450 	 */
451 	BUILD_ASSERT(CONFIG_ETH_NATIVE_POSIX_INTERFACE_COUNT == 1,
452 		     "Cannot have static MAC if interface count > 1");
453 
454 	if (CONFIG_ETH_NATIVE_POSIX_MAC_ADDR[0] != 0) {
455 		if (net_bytes_from_str(ctx->mac_addr, sizeof(ctx->mac_addr),
456 				       CONFIG_ETH_NATIVE_POSIX_MAC_ADDR) < 0) {
457 			LOG_ERR("Invalid MAC address %s",
458 				CONFIG_ETH_NATIVE_POSIX_MAC_ADDR);
459 		}
460 	}
461 #endif
462 
463 	/* If we have only one network interface, then use the name
464 	 * defined in the Kconfig directly. This way there is no need to
465 	 * change the documentation etc. and break things.
466 	 */
467 	if (CONFIG_ETH_NATIVE_POSIX_INTERFACE_COUNT == 1) {
468 		ctx->if_name = CONFIG_ETH_NATIVE_POSIX_DRV_NAME;
469 	}
470 
471 	LOG_DBG("Interface %p using \"%s\"", iface, ctx->if_name);
472 
473 	net_if_set_link_addr(iface, ll_addr->addr, ll_addr->len,
474 			     NET_LINK_ETHERNET);
475 
476 	ctx->dev_fd = eth_iface_create(CONFIG_ETH_NATIVE_POSIX_DEV_NAME, ctx->if_name, false);
477 	if (ctx->dev_fd < 0) {
478 		LOG_ERR("Cannot create %s (%d)", ctx->if_name, -errno);
479 	} else {
480 		/* Create a thread that will handle incoming data from host */
481 		create_rx_handler(ctx);
482 	}
483 }
484 
485 static
eth_posix_native_get_capabilities(const struct device * dev)486 enum ethernet_hw_caps eth_posix_native_get_capabilities(const struct device *dev)
487 {
488 	ARG_UNUSED(dev);
489 
490 	return ETHERNET_TXTIME
491 #if defined(CONFIG_NET_VLAN)
492 		| ETHERNET_HW_VLAN
493 #endif
494 #if defined(CONFIG_ETH_NATIVE_POSIX_VLAN_TAG_STRIP)
495 		| ETHERNET_HW_VLAN_TAG_STRIP
496 #endif
497 #if defined(CONFIG_ETH_NATIVE_POSIX_PTP_CLOCK)
498 		| ETHERNET_PTP
499 #endif
500 #if defined(CONFIG_NET_PROMISCUOUS_MODE)
501 		| ETHERNET_PROMISC_MODE
502 #endif
503 #if defined(CONFIG_NET_LLDP)
504 		| ETHERNET_LLDP
505 #endif
506 		;
507 }
508 
509 #if defined(CONFIG_ETH_NATIVE_POSIX_PTP_CLOCK)
eth_get_ptp_clock(const struct device * dev)510 static const struct device *eth_get_ptp_clock(const struct device *dev)
511 {
512 	struct eth_context *context = dev->data;
513 
514 	return context->ptp_clock;
515 }
516 #endif
517 
518 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
get_stats(const struct device * dev)519 static struct net_stats_eth *get_stats(const struct device *dev)
520 {
521 	struct eth_context *context = dev->data;
522 
523 	return &(context->stats);
524 }
525 #endif
526 
set_config(const struct device * dev,enum ethernet_config_type type,const struct ethernet_config * config)527 static int set_config(const struct device *dev,
528 		      enum ethernet_config_type type,
529 		      const struct ethernet_config *config)
530 {
531 	int ret = 0;
532 
533 	if (IS_ENABLED(CONFIG_NET_PROMISCUOUS_MODE) &&
534 	    type == ETHERNET_CONFIG_TYPE_PROMISC_MODE) {
535 		struct eth_context *context = dev->data;
536 
537 		if (config->promisc_mode) {
538 			if (context->promisc_mode) {
539 				return -EALREADY;
540 			}
541 
542 			context->promisc_mode = true;
543 		} else {
544 			if (!context->promisc_mode) {
545 				return -EALREADY;
546 			}
547 
548 			context->promisc_mode = false;
549 		}
550 
551 		ret = eth_promisc_mode(context->if_name,
552 				       context->promisc_mode);
553 	} else if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) {
554 		struct eth_context *context = dev->data;
555 
556 		memcpy(context->mac_addr, config->mac_address.addr,
557 		       sizeof(context->mac_addr));
558 	}
559 
560 	return ret;
561 }
562 
563 #if defined(CONFIG_NET_VLAN)
vlan_setup(const struct device * dev,struct net_if * iface,uint16_t tag,bool enable)564 static int vlan_setup(const struct device *dev, struct net_if *iface,
565 		      uint16_t tag, bool enable)
566 {
567 	if (enable) {
568 		net_lldp_set_lldpdu(iface);
569 	} else {
570 		net_lldp_unset_lldpdu(iface);
571 	}
572 
573 	return 0;
574 }
575 #endif /* CONFIG_NET_VLAN */
576 
577 static const struct ethernet_api eth_if_api = {
578 	.iface_api.init = eth_iface_init,
579 
580 	.get_capabilities = eth_posix_native_get_capabilities,
581 	.set_config = set_config,
582 	.send = eth_send,
583 
584 #if defined(CONFIG_NET_VLAN)
585 	.vlan_setup = vlan_setup,
586 #endif
587 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
588 	.get_stats = get_stats,
589 #endif
590 #if defined(CONFIG_ETH_NATIVE_POSIX_PTP_CLOCK)
591 	.get_ptp_clock = eth_get_ptp_clock,
592 #endif
593 };
594 
595 #define DEFINE_ETH_DEV_DATA(x, _)					     \
596 	static struct eth_context eth_context_data_##x = {		     \
597 		.if_name = CONFIG_ETH_NATIVE_POSIX_DRV_NAME #x,		     \
598 		.rx_thread = &rx_thread_data_##x,			     \
599 		.rx_stack = rx_thread_stack_##x,			     \
600 		.rx_stack_size = K_KERNEL_STACK_SIZEOF(rx_thread_stack_##x), \
601 	}
602 
603 LISTIFY(CONFIG_ETH_NATIVE_POSIX_INTERFACE_COUNT, DEFINE_ETH_DEV_DATA, (;), _);
604 
605 #define DEFINE_ETH_DEVICE(x, _)						\
606 	ETH_NET_DEVICE_INIT(eth_native_posix_##x,			\
607 			    CONFIG_ETH_NATIVE_POSIX_DRV_NAME #x,	\
608 			    NULL, NULL,	&eth_context_data_##x, NULL,	\
609 			    CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,	\
610 			    &eth_if_api,				\
611 			    NET_ETH_MTU)
612 
613 LISTIFY(CONFIG_ETH_NATIVE_POSIX_INTERFACE_COUNT, DEFINE_ETH_DEVICE, (;), _);
614 
615 #if defined(CONFIG_ETH_NATIVE_POSIX_PTP_CLOCK)
616 
617 #if defined(CONFIG_NET_GPTP)
618 BUILD_ASSERT(								\
619 	CONFIG_ETH_NATIVE_POSIX_INTERFACE_COUNT == CONFIG_NET_GPTP_NUM_PORTS, \
620 	"Number of network interfaces must match gPTP port count");
621 #endif
622 
623 struct ptp_context {
624 	struct eth_context *eth_context;
625 };
626 
627 #define DEFINE_PTP_DEV_DATA(x, _) \
628 	static struct ptp_context ptp_context_##x
629 
630 LISTIFY(CONFIG_ETH_NATIVE_POSIX_INTERFACE_COUNT, DEFINE_PTP_DEV_DATA, (;), _);
631 
ptp_clock_set_native_posix(const struct device * clk,struct net_ptp_time * tm)632 static int ptp_clock_set_native_posix(const struct device *clk,
633 				      struct net_ptp_time *tm)
634 {
635 	ARG_UNUSED(clk);
636 	ARG_UNUSED(tm);
637 
638 	/* We cannot set the host device time so this function
639 	 * does nothing.
640 	 */
641 
642 	return 0;
643 }
644 
ptp_clock_get_native_posix(const struct device * clk,struct net_ptp_time * tm)645 static int ptp_clock_get_native_posix(const struct device *clk,
646 				      struct net_ptp_time *tm)
647 {
648 	ARG_UNUSED(clk);
649 
650 	return eth_clock_gettime(&tm->second, &tm->nanosecond);
651 }
652 
ptp_clock_adjust_native_posix(const struct device * clk,int increment)653 static int ptp_clock_adjust_native_posix(const struct device *clk,
654 					 int increment)
655 {
656 	ARG_UNUSED(clk);
657 	ARG_UNUSED(increment);
658 
659 	/* We cannot adjust the host device time so this function
660 	 * does nothing.
661 	 */
662 
663 	return 0;
664 }
665 
ptp_clock_rate_adjust_native_posix(const struct device * clk,double ratio)666 static int ptp_clock_rate_adjust_native_posix(const struct device *clk,
667 					      double ratio)
668 {
669 	ARG_UNUSED(clk);
670 	ARG_UNUSED(ratio);
671 
672 	/* We cannot adjust the host device time so this function
673 	 * does nothing.
674 	 */
675 
676 	return 0;
677 }
678 
679 static const struct ptp_clock_driver_api api = {
680 	.set = ptp_clock_set_native_posix,
681 	.get = ptp_clock_get_native_posix,
682 	.adjust = ptp_clock_adjust_native_posix,
683 	.rate_adjust = ptp_clock_rate_adjust_native_posix,
684 };
685 
686 #define PTP_INIT_FUNC(x, _)						\
687 	static int ptp_init_##x(const struct device *port)			\
688 	{								\
689 		const struct device *const eth_dev = DEVICE_GET(eth_native_posix_##x); \
690 		struct eth_context *context = eth_dev->data;	\
691 		struct ptp_context *ptp_context = port->data;	\
692 									\
693 		context->ptp_clock = port;				\
694 		ptp_context->eth_context = context;			\
695 									\
696 		return 0;						\
697 	}
698 
699 LISTIFY(CONFIG_ETH_NATIVE_POSIX_INTERFACE_COUNT, PTP_INIT_FUNC, (), _)
700 
701 #define DEFINE_PTP_DEVICE(x, _)						\
702 	DEVICE_DEFINE(eth_native_posix_ptp_clock_##x,			\
703 			    PTP_CLOCK_NAME "_" #x,			\
704 			    ptp_init_##x,				\
705 			    NULL,					\
706 			    &ptp_context_##x,				\
707 			    NULL,					\
708 			    POST_KERNEL,				\
709 			    CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,	\
710 			    &api)
711 
712 LISTIFY(CONFIG_ETH_NATIVE_POSIX_INTERFACE_COUNT, DEFINE_PTP_DEVICE, (;), _);
713 
714 #endif /* CONFIG_ETH_NATIVE_POSIX_PTP_CLOCK */
715