]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-lldp.c
util: split out escaping code into escape.[ch]
[thirdparty/systemd.git] / src / libsystemd-network / test-lldp.c
CommitLineData
ad1ad5c8
SS
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>
ad1ad5c8 24#include <string.h>
ad1ad5c8 25#include <net/ethernet.h>
ad1ad5c8
SS
26#include <arpa/inet.h>
27
6fd255cf
BG
28#include "sd-lldp.h"
29#include "sd-event.h"
30#include "event-util.h"
ad1ad5c8
SS
31#include "macro.h"
32#include "lldp.h"
33#include "lldp-tlv.h"
6fd255cf 34#include "lldp-network.h"
ad1ad5c8
SS
35
36#define TEST_LLDP_PORT "em1"
37#define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
38#define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
39
6fd255cf
BG
40static int test_fd[2];
41
ad1ad5c8
SS
42static struct ether_addr mac_addr = {
43 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
44};
45
46static int lldp_build_tlv_packet(tlv_packet **ret) {
176c355b 47 _cleanup_lldp_packet_unref_ tlv_packet *m = NULL;
ad1ad5c8 48 const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
804138a0
LP
49 struct ether_header ether = {
50 .ether_type = htons(ETHERTYPE_LLDP),
51 };
ad1ad5c8
SS
52
53 /* Append ethernet header */
ad1ad5c8
SS
54 memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
55 memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
ad1ad5c8
SS
56
57 assert_se(tlv_packet_new(&m) >= 0);
58
59 assert_se(tlv_packet_append_bytes(m, &ether, sizeof(struct ether_header)) >= 0);
60
61 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
62
63 assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0);
64 assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0);
65
66 assert_se(lldp_tlv_packet_close_container(m) >= 0);
67
68 /* port name */
69 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0);
70
71 assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0);
72 assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0);
73
74 assert_se(lldp_tlv_packet_close_container(m) >= 0);
75
76 /* ttl */
77 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0);
78
79 assert_se(tlv_packet_append_u16(m, 170) >= 0);
80
81 assert_se(lldp_tlv_packet_close_container(m) >= 0);
82
83 /* system name */
84 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
85
86 assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME,
87 strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0);
88 assert_se(lldp_tlv_packet_close_container(m) >= 0);
89
90 /* system descrition */
91 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
92
93 assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC,
94 strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0);
95
96 assert_se(lldp_tlv_packet_close_container(m) >= 0);
97
98 /* Mark end of packet */
99 assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0);
100 assert_se(lldp_tlv_packet_close_container(m) >= 0);
101
102 *ret = m;
103
104 m = NULL;
105
106 return 0;
107}
108
109static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) {
110 uint8_t *p, subtype;
111 uint16_t length;
112
113 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
114 assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
115
116 switch (subtype) {
117 case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
118
119 *type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS;
120 assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0);
121
122 assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0);
123
124 break;
125 default:
126 assert_not_reached("Unhandled option");
127 }
128
129 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
130
131 return 0;
132}
133
134static int lldp_parse_port_id_tlv(tlv_packet *m) {
33256079
LP
135 _cleanup_free_ char *p = NULL;
136 char *str = NULL;
ad1ad5c8
SS
137 uint16_t length;
138 uint8_t subtype;
139
140 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0);
141
142 assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
143
144 switch (subtype) {
145 case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
146 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
147
b762fbd1 148 p = strndup(str, length-1);
889cec8d 149 assert_se(p);
ad1ad5c8
SS
150
151 assert_se(streq(p, TEST_LLDP_PORT) == 1);
152 break;
153 default:
154 assert_not_reached("Unhandled option");
155 }
156
157 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
158
159 return 0;
160}
161
162static int lldp_parse_system_name_tlv(tlv_packet *m) {
33256079
LP
163 _cleanup_free_ char *p = NULL;
164 char *str = NULL;
ad1ad5c8
SS
165 uint16_t length;
166
167 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
168 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
169
b762fbd1 170 p = strndup(str, length);
2e1a569b 171 assert_se(p);
ad1ad5c8
SS
172
173 assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1);
174
175 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
176
177 return 1;
178}
179
180static int lldp_parse_system_desc_tlv(tlv_packet *m) {
33256079
LP
181 _cleanup_free_ char *p = NULL;
182 char *str = NULL;
ad1ad5c8
SS
183 uint16_t length;
184
185 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
186 assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
187
b762fbd1 188 p = strndup(str, length);
889cec8d 189 assert_se(p);
ad1ad5c8
SS
190
191 assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1);
192
193 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
194
195 return 0;
196}
197
198static int lldp_parse_ttl_tlv(tlv_packet *m) {
199 uint16_t ttl;
200
201 assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0);
202 assert_se(tlv_packet_read_u16(m, &ttl) >= 0);
203
204 assert_se(ttl == 170);
205
206 assert_se(lldp_tlv_packet_exit_container(m) >= 0);
207
208 return 0;
209}
210
4fc6de5d
BG
211static int lldp_get_destination_type(tlv_packet *m) {
212 int dest;
213
214 assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0);
215 assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE);
216
217 return 0;
218}
219
ad1ad5c8
SS
220static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
221 uint8_t subtype;
222
223 assert_se(tlv_packet_parse_pdu(m, len) >= 0);
224 assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0);
225 assert_se(lldp_parse_port_id_tlv(m) >= 0);
226 assert_se(lldp_parse_system_name_tlv(m) >= 0);
227 assert_se(lldp_parse_ttl_tlv(m) >= 0);
228 assert_se(lldp_parse_system_desc_tlv(m) >= 0);
229
4fc6de5d
BG
230 assert_se(lldp_get_destination_type(m) >= 0);
231
ad1ad5c8
SS
232 return 0;
233}
234
6fd255cf 235static void test_parser(void) {
176c355b 236 _cleanup_lldp_packet_unref_ tlv_packet *tlv = NULL;
ad1ad5c8
SS
237
238 /* form a packet */
239 lldp_build_tlv_packet(&tlv);
ad1ad5c8
SS
240 /* parse the packet */
241 tlv_packet_parse_pdu(tlv, tlv->length);
ad1ad5c8
SS
242 /* verify */
243 lldp_parse_tlv_packet(tlv, tlv->length);
6fd255cf
BG
244}
245
246int lldp_network_bind_raw_socket(int ifindex) {
247 if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
248 return -errno;
249
250 return test_fd[0];
251}
252
253static int lldp_handler_calls;
254static void lldp_handler (sd_lldp *lldp, int event, void *userdata) {
255 lldp_handler_calls++;
256}
257
258static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_cb_t cb, void *cb_data) {
259 int r;
260
261 r = sd_lldp_new(42, "dummy", &mac_addr, lldp);
262 if (r)
263 return r;
264
265 r = sd_lldp_attach_event(*lldp, e, 0);
266 if (r)
267 return r;
268
269 r = sd_lldp_set_callback(*lldp, cb, cb_data);
270 if (r)
271 return r;
272
273 r = sd_lldp_start(*lldp);
274 if (r)
275 return r;
276
277 return 0;
278}
279
280static int stop_lldp(sd_lldp *lldp) {
281 int r;
282
283 r = sd_lldp_stop(lldp);
284 if (r)
285 return r;
286
287 r = sd_lldp_detach_event(lldp);
288 if (r)
289 return r;
290
291 sd_lldp_free(lldp);
292 safe_close(test_fd[1]);
293
294 return 0;
295}
296
297static void test_receive_basic_packet(sd_event *e) {
298 sd_lldp *lldp;
299 sd_lldp_packet **packets;
300 uint8_t type, *data;
301 uint16_t length, ttl;
302 int dest_type;
303 char *str;
304 uint8_t frame[] = {
305 /* Ethernet header */
306 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
307 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
308 0x88, 0xcc, /* Ethertype */
309 /* LLDP mandatory TLVs */
310 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
311 0x03, 0x04, 0x05,
312 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
313 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
314 /* LLDP optional TLVs */
315 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */
316 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */
317 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */
318 0x00, 0x00 /* End Of LLDPDU */
319 };
320
321 lldp_handler_calls = 0;
322 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
323
324 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
325 sd_event_run(e, 0);
326 assert_se(lldp_handler_calls == 1);
327 assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
328
329 assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0);
330 assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS);
331 assert_se(length == ETH_ALEN);
332 assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN));
333
334 assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0);
335 assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME);
336 assert_se(length == 3);
337 assert_se(strneq((char *) data, "1/3", 3));
338
339 assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0);
340 assert_se(length == 4);
341 assert_se(strneq(str, "Port", 4));
342
343 assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0);
344 assert_se(length == 3);
345 assert_se(strneq(str, "SYS", 3));
346
347 assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0);
348 assert_se(length == 4); /* This is the real length in the TLV packet */
349 assert_se(strneq(str, "foo", 3));
350
351 assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0);
352 assert_se(ttl == 120);
353
354 assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0);
355 assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE);
356
357 sd_lldp_packet_unref(packets[0]);
358 free(packets);
359
360 assert_se(stop_lldp(lldp) == 0);
361}
362
363static void test_receive_incomplete_packet(sd_event *e) {
364 sd_lldp *lldp;
365 sd_lldp_packet **packets;
366 uint8_t frame[] = {
367 /* Ethernet header */
368 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
369 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
370 0x88, 0xcc, /* Ethertype */
371 /* LLDP mandatory TLVs */
372 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
373 0x03, 0x04, 0x05,
374 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
375 /* Missing TTL */
376 0x00, 0x00 /* End Of LLDPDU */
377 };
378
379 lldp_handler_calls = 0;
380 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
381
382 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
383 sd_event_run(e, 0);
384 assert_se(lldp_handler_calls == 0);
385 assert_se(sd_lldp_get_packets(lldp, &packets) == 0);
386
387 assert_se(stop_lldp(lldp) == 0);
388}
389
390static void test_receive_oui_packet(sd_event *e) {
391 sd_lldp *lldp;
392 sd_lldp_packet **packets;
393 uint32_t id32;
394 uint16_t id16, len;
395 uint8_t flags;
396 char *str;
397 uint8_t frame[] = {
398 /* Ethernet header */
399 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
400 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
401 0x88, 0xcc, /* Ethertype */
402 /* LLDP mandatory TLVs */
403 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
404 0x03, 0x04, 0x05,
405 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */
406 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
407 /* LLDP optional TLVs */
408 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */
409 0x12, 0x34,
410 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */
411 0x01, 0x77, 0x88,
412 0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */
413 0x12, 0x34, 0x06, 0x56, 0x6c, 0x61,
414 0x6e, 0x35, 0x31,
415 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */
416 0x01, 0x02,
417 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */
418 0x01, 0x00, 0x14, 0x00, 0x12,
419 0x00, 0x00 /* End of LLDPDU */
420 };
421
422 lldp_handler_calls = 0;
423 assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
424
425 assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
426 sd_event_run(e, 0);
427 assert_se(lldp_handler_calls == 1);
428 assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
429
430 assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0);
431 assert_se(id16 == 0x1234);
432
433 assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0);
434 assert_se(flags == 1);
435 assert_se(id16 == 0x7788);
436
437 assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0);
438 assert_se(id16 == 0x1234);
439 assert_se(len == 6);
440 assert_se(strneq(str, "Vlan51", 6));
441
442 assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0);
443 assert_se(id16 == 0x0102);
444
445 assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0);
446 assert_se(flags == 1);
447 assert_se(id32 == 0x00140012);
448
449 sd_lldp_packet_unref(packets[0]);
450 free(packets);
451
452 assert_se(stop_lldp(lldp) == 0);
453}
454
455int main(int argc, char *argv[]) {
456 _cleanup_event_unref_ sd_event *e = NULL;
457
458 test_parser();
459
460 /* LLDP reception tests */
461 assert_se(sd_event_new(&e) == 0);
462 test_receive_basic_packet(e);
463 test_receive_incomplete_packet(e);
464 test_receive_oui_packet(e);
ad1ad5c8
SS
465
466 return 0;
467}