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