1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_lldp_sample, LOG_LEVEL_DBG);
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/ethernet.h>
17
18 static struct lldp_system_name_tlv {
19 uint16_t type_length;
20 uint8_t name[4];
21 } __packed tlv = {
22 .name = { 't', 'e', 's', 't' },
23 };
24
set_optional_tlv(struct net_if * iface)25 static void set_optional_tlv(struct net_if *iface)
26 {
27 NET_DBG("");
28
29 tlv.type_length = htons((LLDP_TLV_SYSTEM_NAME << 9) |
30 ((sizeof(tlv) - sizeof(uint16_t)) & 0x01ff));
31
32 net_lldp_config_optional(iface, (uint8_t *)&tlv, sizeof(tlv));
33 }
34
35 /* User data for the interface callback */
36 struct ud {
37 struct net_if *first;
38 struct net_if *second;
39 };
40
iface_cb(struct net_if * iface,void * user_data)41 static void iface_cb(struct net_if *iface, void *user_data)
42 {
43 struct ud *ud = user_data;
44
45 if (net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL)) {
46 return;
47 }
48
49 if (!ud->first) {
50 ud->first = iface;
51 return;
52 }
53
54 if (!ud->second) {
55 ud->second = iface;
56 return;
57 }
58 }
59
setup_iface(struct net_if * eth_iface,struct net_if * iface,const char * ipv6_addr,const char * ipv4_addr,uint16_t vlan_tag)60 static int setup_iface(struct net_if *eth_iface,
61 struct net_if *iface,
62 const char *ipv6_addr,
63 const char *ipv4_addr,
64 uint16_t vlan_tag)
65 {
66 struct net_if_addr *ifaddr;
67 struct in_addr addr4;
68 struct in6_addr addr6;
69 int ret;
70
71 ret = net_eth_vlan_enable(eth_iface, vlan_tag);
72 if (ret < 0) {
73 LOG_ERR("Cannot enable VLAN for tag %d (%d)", vlan_tag, ret);
74 }
75
76 if (net_addr_pton(AF_INET6, ipv6_addr, &addr6)) {
77 LOG_ERR("Invalid address: %s", ipv6_addr);
78 return -EINVAL;
79 }
80
81 ifaddr = net_if_ipv6_addr_add(iface, &addr6, NET_ADDR_MANUAL, 0);
82 if (!ifaddr) {
83 LOG_ERR("Cannot add %s to interface %p", ipv6_addr, iface);
84 return -EINVAL;
85 }
86
87 if (net_addr_pton(AF_INET, ipv4_addr, &addr4)) {
88 LOG_ERR("Invalid address: %s", ipv4_addr);
89 return -EINVAL;
90 }
91
92 ifaddr = net_if_ipv4_addr_add(iface, &addr4, NET_ADDR_MANUAL, 0);
93 if (!ifaddr) {
94 LOG_ERR("Cannot add %s to interface %p", ipv4_addr, iface);
95 return -EINVAL;
96 }
97
98 LOG_DBG("Interface %p VLAN tag %d setup done.", iface, vlan_tag);
99
100 return 0;
101 }
102
103 static struct ud ud;
104
init_vlan(struct net_if * iface)105 static int init_vlan(struct net_if *iface)
106 {
107 enum ethernet_hw_caps caps;
108 int ret;
109
110 (void)memset(&ud, 0, sizeof(ud));
111
112 net_if_foreach(iface_cb, &ud);
113
114 caps = net_eth_get_hw_capabilities(iface);
115 if (!(caps & ETHERNET_HW_VLAN)) {
116 LOG_DBG("Interface %p does not support %s", iface, "VLAN");
117 return -ENOENT;
118 }
119
120 ret = setup_iface(iface, ud.first,
121 CONFIG_NET_SAMPLE_IFACE2_MY_IPV6_ADDR,
122 CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_ADDR,
123 CONFIG_NET_SAMPLE_IFACE2_VLAN_TAG);
124 if (ret < 0) {
125 return ret;
126 }
127
128 ret = setup_iface(iface, ud.second,
129 CONFIG_NET_SAMPLE_IFACE3_MY_IPV6_ADDR,
130 CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_ADDR,
131 CONFIG_NET_SAMPLE_IFACE3_VLAN_TAG);
132 if (ret < 0) {
133 return ret;
134 }
135
136 /* Bring up the VLAN interface automatically */
137 net_if_up(ud.first);
138 net_if_up(ud.second);
139
140 return 0;
141 }
142
parse_lldp(struct net_if * iface,struct net_pkt * pkt)143 static enum net_verdict parse_lldp(struct net_if *iface, struct net_pkt *pkt)
144 {
145 LOG_DBG("iface %p Parsing LLDP, len %zu", iface, net_pkt_get_len(pkt));
146
147 net_pkt_cursor_init(pkt);
148
149 while (1) {
150 uint16_t type_length;
151 uint16_t length;
152 uint8_t type;
153
154 if (net_pkt_read_be16(pkt, &type_length)) {
155 LOG_DBG("End LLDP DU TLV");
156 break;
157 }
158
159 length = type_length & 0x1FF;
160 type = (uint8_t)(type_length >> 9);
161
162 /* Skip for now data */
163 if (net_pkt_skip(pkt, length)) {
164 LOG_DBG("");
165 break;
166 }
167
168 switch (type) {
169 case LLDP_TLV_CHASSIS_ID:
170 LOG_DBG("Chassis ID");
171 break;
172 case LLDP_TLV_PORT_ID:
173 LOG_DBG("Port ID");
174 break;
175 case LLDP_TLV_TTL:
176 LOG_DBG("TTL");
177 break;
178 default:
179 LOG_DBG("TLV Not parsed");
180 break;
181 }
182
183 LOG_DBG("type_length %u type %u length %u",
184 type_length, type, length);
185 }
186
187 /* Let stack to free the packet */
188 return NET_DROP;
189 }
190
init_app(void)191 static int init_app(void)
192 {
193 enum ethernet_hw_caps caps;
194 struct net_if *iface;
195 int ret;
196
197 iface = net_if_get_first_by_type(&NET_L2_GET_NAME(ETHERNET));
198 if (!iface) {
199 LOG_ERR("No ethernet interfaces found.");
200 return -ENOENT;
201 }
202
203 ret = init_vlan(iface);
204 if (ret < 0) {
205 LOG_WRN("Cannot setup VLAN (%d)", ret);
206 }
207
208 caps = net_eth_get_hw_capabilities(iface);
209 if (!(caps & ETHERNET_LLDP)) {
210 LOG_ERR("Interface %p does not support %s", iface, "LLDP");
211 LOG_ERR("Cannot continue!");
212 return -ENOENT;
213 }
214
215 set_optional_tlv(iface);
216 net_lldp_register_callback(iface, parse_lldp);
217
218 return 0;
219 }
220
main(void)221 int main(void)
222 {
223 /* The application will setup VLAN but does nothing meaningful.
224 * The configuration will enable LLDP support so you should see
225 * LLDPDU messages sent to the network interface.
226 */
227 init_app();
228 return 0;
229 }
230