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