]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-lldp.c
networkd: Introduce Link Layer Discovery Protocol (LLDP)
[thirdparty/systemd.git] / src / libsystemd-network / test-lldp.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright (C) 2014 Tom Gundersen
7 Copyright (C) 2014 Susant Sahani
8
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <linux/if.h>
28 #include <linux/if_ether.h>
29 #include <net/ethernet.h>
30 #include <sys/types.h>
31 #include <arpa/inet.h>
32
33 #include "macro.h"
34 #include "lldp.h"
35 #include "lldp-tlv.h"
36
37 #define TEST_LLDP_PORT "em1"
38 #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
39 #define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
40
41 static struct ether_addr mac_addr = {
42 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
43 };
44
45 static int lldp_build_tlv_packet(tlv_packet **ret) {
46 _cleanup_tlv_packet_free_ tlv_packet *m = NULL;
47 const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
48 struct ether_header ether;
49
50 /* Append ethernet header */
51 memset(&ether, 0, sizeof(ether));
52 memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
53 memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
54 ether.ether_type = htons(ETHERTYPE_LLDP);
55
56 assert_se(tlv_packet_new(&m) >= 0);
57
58 assert_se(tlv_packet_append_bytes(m, &ether, sizeof(struct ether_header)) >= 0);
59
60 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
61
62 assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0);
63 assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0);
64
65 assert_se(lldp_tlv_packet_close_container(m) >= 0);
66
67 /* port name */
68 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0);
69
70 assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0);
71 assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0);
72
73 assert_se(lldp_tlv_packet_close_container(m) >= 0);
74
75 /* ttl */
76 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0);
77
78 assert_se(tlv_packet_append_u16(m, 170) >= 0);
79
80 assert_se(lldp_tlv_packet_close_container(m) >= 0);
81
82 /* system name */
83 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
84
85 assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME,
86 strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0);
87 assert_se(lldp_tlv_packet_close_container(m) >= 0);
88
89 /* system descrition */
90 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
91
92 assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC,
93 strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0);
94
95 assert_se(lldp_tlv_packet_close_container(m) >= 0);
96
97 /* Mark end of packet */
98 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0);
99 assert_se(lldp_tlv_packet_close_container(m) >= 0);
100
101 *ret = m;
102
103 m = NULL;
104
105 return 0;
106 }
107
108 static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) {
109 uint8_t *p, subtype;
110 uint16_t length;
111
112 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
113 assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
114
115 switch (subtype) {
116 case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
117
118 *type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS;
119 assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0);
120
121 assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0);
122
123 break;
124 default:
125 assert_not_reached("Unhandled option");
126 }
127
128 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
129
130 return 0;
131 }
132
133 static int lldp_parse_port_id_tlv(tlv_packet *m) {
134 char *str = NULL, *p;
135 uint16_t length;
136 uint8_t subtype;
137
138 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0);
139
140 assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
141
142 switch (subtype) {
143 case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
144 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
145
146 p = malloc0(length + 1);
147 strncpy(p, str, length-1);
148
149 assert_se(streq(p, TEST_LLDP_PORT) == 1);
150 break;
151 default:
152 assert_not_reached("Unhandled option");
153 }
154
155 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
156
157 return 0;
158 }
159
160 static int lldp_parse_system_name_tlv(tlv_packet *m) {
161 char *str = NULL, *p;
162 uint16_t length;
163
164 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
165 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
166
167 p = malloc0(length + 1);
168 strncpy(p, str, length);
169
170 assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1);
171
172 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
173
174 return 1;
175 }
176
177 static int lldp_parse_system_desc_tlv(tlv_packet *m) {
178 char *str = NULL, *p;
179 uint16_t length;
180
181 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
182 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
183
184 p = malloc0(length + 1);
185 strncpy(p, str, length);
186
187 assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1);
188
189 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
190
191 return 0;
192 }
193
194 static int lldp_parse_ttl_tlv(tlv_packet *m) {
195 uint16_t ttl;
196
197 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0);
198 assert_se(tlv_packet_read_u16(m, &ttl) >= 0);
199
200 assert_se(ttl == 170);
201
202 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
203
204 return 0;
205 }
206
207 static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
208 uint8_t subtype;
209
210 assert_se(tlv_packet_parse_pdu(m, len) >= 0);
211 assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0);
212 assert_se(lldp_parse_port_id_tlv(m) >= 0);
213 assert_se(lldp_parse_system_name_tlv(m) >= 0);
214 assert_se(lldp_parse_ttl_tlv(m) >= 0);
215 assert_se(lldp_parse_system_desc_tlv(m) >= 0);
216
217 return 0;
218 }
219
220 int main(int argc, char *argv[]) {
221 _cleanup_tlv_packet_free_ tlv_packet *tlv = NULL;
222
223 /* form a packet */
224 lldp_build_tlv_packet(&tlv);
225
226 /* parse the packet */
227 tlv_packet_parse_pdu(tlv, tlv->length);
228
229 /* verify */
230 lldp_parse_tlv_packet(tlv, tlv->length);
231
232 return 0;
233 }