1 /*
2  * Copyright (c) 2020 DENX Software Engineering GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef __DSA_SAMPLE__
8 #define __DSA_SAMPLE__
9 
10 #include <zephyr/kernel.h>
11 #include <errno.h>
12 
13 #include <zephyr/net/net_core.h>
14 #include <zephyr/net/net_l2.h>
15 #include <zephyr/net/net_if.h>
16 #include <zephyr/net/socket.h>
17 #include <zephyr/net/ethernet.h>
18 
19 #define MCAST_DEST_MAC0 0x01
20 #define MCAST_DEST_MAC1 0x80
21 #define MCAST_DEST_MAC2 0xc2
22 #define MCAST_DEST_MAC3 0x00
23 #define MCAST_DEST_MAC4 0x00
24 #define MCAST_DEST_MAC5 0x03
25 
26 #define RECV_BUFFER_SIZE 1280
27 #define ETH_ALEN 6
28 #define PACKET_LEN 128
29 
30 extern struct ud user_data_ifaces;
31 
32 struct eth_addr {
33 	uint8_t addr[ETH_ALEN]; /* origin hardware address */
34 };
35 
36 struct instance_data {
37 	char *if_name;
38 	int sock;
39 	char recv_buffer[RECV_BUFFER_SIZE];
40 };
41 
42 /* User data for the interface callback */
43 struct ud {
44 	struct net_if *lan[3];
45 	struct net_if *master;
46 };
47 
check_ll_ether_addr(const uint8_t * a,const uint8_t * b)48 static inline bool check_ll_ether_addr(const uint8_t *a, const uint8_t *b)
49 {
50 	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]) |
51 		(a[3] ^ b[3]) | (a[4] ^ b[4]) | (a[5] ^ b[5])) == 0;
52 }
53 
dsa_buf_write_be16(uint16_t tl,uint8_t ** p)54 static inline void dsa_buf_write_be16(uint16_t tl, uint8_t **p)
55 {
56 	uint8_t *v = (uint8_t *) &tl;
57 	**p = v[1];
58 	(*p)++;
59 	**p = v[0];
60 	(*p)++;
61 }
62 
63 int start_slave_port_packet_socket(struct net_if *iface,
64 				   struct instance_data *pd);
65 
66 enum net_verdict dsa_ll_addr_switch_cb(struct net_if *iface,
67 				       struct net_pkt *pkt);
68 
69 #define CMD_DISCOVER 0
70 #define CMD_ACK      1
71 #define DSA_STACK_SIZE 4096
72 #define DSA_PRIORITY      5
73 #define DSA_THREAD_START_DELAY 4000
74 
75 #define DSA_THREAD(ID, FN_RECV, FN_SEND)                                       \
76 	static void dsa_thread_##ID(void *t1, void *t2, void *t3);             \
77 	K_THREAD_DEFINE(dsa_tid_##ID, DSA_STACK_SIZE,                          \
78 		dsa_thread_##ID, NULL, NULL, NULL,                             \
79 			DSA_PRIORITY, 0, DSA_THREAD_START_DELAY);              \
80 									       \
81 	void dsa_thread_##ID(void *t1, void *t2, void *t3)                     \
82 	{                                                                      \
83 		int origin_port, ret;                                          \
84 		uint16_t seq;                                                  \
85 		struct eth_addr origin_addr;                                   \
86 		struct instance_data data;                                     \
87 		struct net_if *iface;                                          \
88 									       \
89 		iface = user_data_ifaces.lan[ID-1];                            \
90 									       \
91 		data.if_name = "lan"#ID;                                       \
92 		ret = start_slave_port_packet_socket(iface, &data);            \
93 		if (ret < 0) {                                                 \
94 			LOG_ERR("start_slave_port_packet_socket failed %d",    \
95 				ret);                                          \
96 			return;                                                \
97 		}                                                              \
98 		dsa_register_recv_callback(iface,                              \
99 						dsa_ll_addr_switch_cb);        \
100 									       \
101 		LOG_INF("DSA -> eth/lan"#ID" idx: %d sock: %d",                \
102 			net_if_get_by_iface(iface), data.sock);                \
103 		do {                                                           \
104 			ret = FN_RECV(iface, &data, &seq,                      \
105 					&origin_port, &origin_addr);           \
106 			if (ret) {                                             \
107 				break;                                         \
108 			}                                                      \
109 			ret = FN_SEND(iface, &data,                            \
110 					seq, 0, origin_port, CMD_ACK,          \
111 					&origin_addr);                         \
112 			if (ret) {                                             \
113 				break;                                         \
114 			}                                                      \
115 		} while (true);                                                \
116 	}
117 
118 #endif /* __DSA_SAMPLE__ */
119