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