1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 Tom Gundersen
7 Copyright (C) 2014 Susant Sahani
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.
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.
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/>.
23 #include <arpa/inet.h>
24 #include <net/ethernet.h>
31 #include "event-util.h"
32 #include "lldp-network.h"
36 #include "string-util.h"
38 #define TEST_LLDP_PORT "em1"
39 #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
40 #define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
42 static int test_fd
[2];
44 static struct ether_addr mac_addr
= {
45 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
48 static int lldp_build_tlv_packet(tlv_packet
**ret
) {
49 _cleanup_lldp_packet_unref_ tlv_packet
*m
= NULL
;
50 const uint8_t lldp_dst
[] = LLDP_MULTICAST_ADDR
;
51 struct ether_header ether
= {
52 .ether_type
= htons(ETHERTYPE_LLDP
),
55 /* Append ethernet header */
56 memcpy(ðer
.ether_dhost
, lldp_dst
, ETHER_ADDR_LEN
);
57 memcpy(ðer
.ether_shost
, &mac_addr
, ETHER_ADDR_LEN
);
59 assert_se(tlv_packet_new(&m
) >= 0);
61 assert_se(tlv_packet_append_bytes(m
, ðer
, sizeof(struct ether_header
)) >= 0);
63 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_CHASSIS_ID
) >= 0);
65 assert_se(tlv_packet_append_u8(m
, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS
) >= 0);
66 assert_se(tlv_packet_append_bytes(m
, &mac_addr
, ETHER_ADDR_LEN
) >= 0);
68 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
71 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_PORT_ID
) >= 0);
73 assert_se(tlv_packet_append_u8(m
, LLDP_PORT_SUBTYPE_INTERFACE_NAME
) >= 0);
74 assert_se(tlv_packet_append_bytes(m
, TEST_LLDP_PORT
, strlen(TEST_LLDP_PORT
) + 1) >= 0);
76 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
79 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_TTL
) >= 0);
81 assert_se(tlv_packet_append_u16(m
, 170) >= 0);
83 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
86 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_SYSTEM_NAME
) >= 0);
88 assert_se(tlv_packet_append_bytes(m
, TEST_LLDP_TYPE_SYSTEM_NAME
,
89 strlen(TEST_LLDP_TYPE_SYSTEM_NAME
)) >= 0);
90 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
92 /* system descrition */
93 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_SYSTEM_DESCRIPTION
) >= 0);
95 assert_se(tlv_packet_append_bytes(m
, TEST_LLDP_TYPE_SYSTEM_DESC
,
96 strlen(TEST_LLDP_TYPE_SYSTEM_DESC
)) >= 0);
98 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
100 /* Mark end of packet */
101 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_END
) >= 0);
102 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
111 static int lldp_parse_chassis_tlv(tlv_packet
*m
, uint8_t *type
) {
115 assert_se(lldp_tlv_packet_enter_container(m
, LLDP_TYPE_CHASSIS_ID
) >= 0);
116 assert_se(tlv_packet_read_u8(m
, &subtype
) >= 0);
119 case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS
:
121 *type
= LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS
;
122 assert_se(tlv_packet_read_bytes(m
, &p
, &length
) >= 0);
124 assert_se(memcmp(p
, &mac_addr
.ether_addr_octet
, ETHER_ADDR_LEN
) == 0);
128 assert_not_reached("Unhandled option");
131 assert_se(lldp_tlv_packet_exit_container(m
) >= 0);
136 static int lldp_parse_port_id_tlv(tlv_packet
*m
) {
137 _cleanup_free_
char *p
= NULL
;
142 assert_se(lldp_tlv_packet_enter_container(m
, LLDP_TYPE_PORT_ID
) >= 0);
144 assert_se(tlv_packet_read_u8(m
, &subtype
) >= 0);
147 case LLDP_PORT_SUBTYPE_INTERFACE_NAME
:
148 assert_se(tlv_packet_read_string(m
, &str
, &length
) >= 0);
150 p
= strndup(str
, length
-1);
153 assert_se(streq(p
, TEST_LLDP_PORT
) == 1);
156 assert_not_reached("Unhandled option");
159 assert_se(lldp_tlv_packet_exit_container(m
) >= 0);
164 static int lldp_parse_system_name_tlv(tlv_packet
*m
) {
165 _cleanup_free_
char *p
= NULL
;
169 assert_se(lldp_tlv_packet_enter_container(m
, LLDP_TYPE_SYSTEM_NAME
) >= 0);
170 assert_se(tlv_packet_read_string(m
, &str
, &length
) >= 0);
172 p
= strndup(str
, length
);
175 assert_se(streq(p
, TEST_LLDP_TYPE_SYSTEM_NAME
) == 1);
177 assert_se(lldp_tlv_packet_exit_container(m
) >= 0);
182 static int lldp_parse_system_desc_tlv(tlv_packet
*m
) {
183 _cleanup_free_
char *p
= NULL
;
187 assert_se(lldp_tlv_packet_enter_container(m
, LLDP_TYPE_SYSTEM_DESCRIPTION
) >= 0);
188 assert_se(tlv_packet_read_string(m
, &str
, &length
) >= 0);
190 p
= strndup(str
, length
);
193 assert_se(streq(p
, TEST_LLDP_TYPE_SYSTEM_DESC
) == 1);
195 assert_se(lldp_tlv_packet_exit_container(m
) >= 0);
200 static int lldp_parse_ttl_tlv(tlv_packet
*m
) {
203 assert_se(lldp_tlv_packet_enter_container(m
, LLDP_TYPE_TTL
) >= 0);
204 assert_se(tlv_packet_read_u16(m
, &ttl
) >= 0);
206 assert_se(ttl
== 170);
208 assert_se(lldp_tlv_packet_exit_container(m
) >= 0);
213 static int lldp_get_destination_type(tlv_packet
*m
) {
216 assert_se(sd_lldp_packet_get_destination_type(m
, &dest
) >= 0);
217 assert_se(dest
== SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE
);
222 static int lldp_parse_tlv_packet(tlv_packet
*m
, int len
) {
225 assert_se(tlv_packet_parse_pdu(m
, len
) >= 0);
226 assert_se(lldp_parse_chassis_tlv(m
, &subtype
) >= 0);
227 assert_se(lldp_parse_port_id_tlv(m
) >= 0);
228 assert_se(lldp_parse_system_name_tlv(m
) >= 0);
229 assert_se(lldp_parse_ttl_tlv(m
) >= 0);
230 assert_se(lldp_parse_system_desc_tlv(m
) >= 0);
232 assert_se(lldp_get_destination_type(m
) >= 0);
237 static void test_parser(void) {
238 _cleanup_lldp_packet_unref_ tlv_packet
*tlv
= NULL
;
241 lldp_build_tlv_packet(&tlv
);
242 /* parse the packet */
243 tlv_packet_parse_pdu(tlv
, tlv
->length
);
245 lldp_parse_tlv_packet(tlv
, tlv
->length
);
248 int lldp_network_bind_raw_socket(int ifindex
) {
249 if (socketpair(AF_UNIX
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0, test_fd
) < 0)
255 static int lldp_handler_calls
;
256 static void lldp_handler (sd_lldp
*lldp
, int event
, void *userdata
) {
257 lldp_handler_calls
++;
260 static int start_lldp(sd_lldp
**lldp
, sd_event
*e
, sd_lldp_cb_t cb
, void *cb_data
) {
263 r
= sd_lldp_new(42, "dummy", &mac_addr
, lldp
);
267 r
= sd_lldp_attach_event(*lldp
, e
, 0);
271 r
= sd_lldp_set_callback(*lldp
, cb
, cb_data
);
275 r
= sd_lldp_start(*lldp
);
282 static int stop_lldp(sd_lldp
*lldp
) {
285 r
= sd_lldp_stop(lldp
);
289 r
= sd_lldp_detach_event(lldp
);
294 safe_close(test_fd
[1]);
299 static void test_receive_basic_packet(sd_event
*e
) {
301 sd_lldp_packet
**packets
;
303 uint16_t length
, ttl
;
307 /* Ethernet header */
308 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
309 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
310 0x88, 0xcc, /* Ethertype */
311 /* LLDP mandatory TLVs */
312 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
314 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
315 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
316 /* LLDP optional TLVs */
317 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */
318 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */
319 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */
320 0x00, 0x00 /* End Of LLDPDU */
323 lldp_handler_calls
= 0;
324 assert_se(start_lldp(&lldp
, e
, lldp_handler
, NULL
) == 0);
326 assert_se(write(test_fd
[1], frame
, sizeof(frame
)) == sizeof(frame
));
328 assert_se(lldp_handler_calls
== 1);
329 assert_se(sd_lldp_get_packets(lldp
, &packets
) == 1);
331 assert_se(sd_lldp_packet_read_chassis_id(packets
[0], &type
, &data
, &length
) == 0);
332 assert_se(type
== LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS
);
333 assert_se(length
== ETH_ALEN
);
334 assert_se(!memcmp(data
, "\x00\x01\x02\x03\x04\x05", ETH_ALEN
));
336 assert_se(sd_lldp_packet_read_port_id(packets
[0], &type
, &data
, &length
) == 0);
337 assert_se(type
== LLDP_PORT_SUBTYPE_INTERFACE_NAME
);
338 assert_se(length
== 3);
339 assert_se(strneq((char *) data
, "1/3", 3));
341 assert_se(sd_lldp_packet_read_port_description(packets
[0], &str
, &length
) == 0);
342 assert_se(length
== 4);
343 assert_se(strneq(str
, "Port", 4));
345 assert_se(sd_lldp_packet_read_system_name(packets
[0], &str
, &length
) == 0);
346 assert_se(length
== 3);
347 assert_se(strneq(str
, "SYS", 3));
349 assert_se(sd_lldp_packet_read_system_description(packets
[0], &str
, &length
) == 0);
350 assert_se(length
== 4); /* This is the real length in the TLV packet */
351 assert_se(strneq(str
, "foo", 3));
353 assert_se(sd_lldp_packet_read_ttl(packets
[0], &ttl
) == 0);
354 assert_se(ttl
== 120);
356 assert_se(sd_lldp_packet_get_destination_type(packets
[0], &dest_type
) == 0);
357 assert_se(dest_type
== SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE
);
359 sd_lldp_packet_unref(packets
[0]);
362 assert_se(stop_lldp(lldp
) == 0);
365 static void test_receive_incomplete_packet(sd_event
*e
) {
367 sd_lldp_packet
**packets
;
369 /* Ethernet header */
370 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
371 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
372 0x88, 0xcc, /* Ethertype */
373 /* LLDP mandatory TLVs */
374 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
376 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
378 0x00, 0x00 /* End Of LLDPDU */
381 lldp_handler_calls
= 0;
382 assert_se(start_lldp(&lldp
, e
, lldp_handler
, NULL
) == 0);
384 assert_se(write(test_fd
[1], frame
, sizeof(frame
)) == sizeof(frame
));
386 assert_se(lldp_handler_calls
== 0);
387 assert_se(sd_lldp_get_packets(lldp
, &packets
) == 0);
389 assert_se(stop_lldp(lldp
) == 0);
392 static void test_receive_oui_packet(sd_event
*e
) {
394 sd_lldp_packet
**packets
;
400 /* Ethernet header */
401 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
402 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
403 0x88, 0xcc, /* Ethertype */
404 /* LLDP mandatory TLVs */
405 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
407 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */
408 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
409 /* LLDP optional TLVs */
410 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */
412 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */
414 0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */
415 0x12, 0x34, 0x06, 0x56, 0x6c, 0x61,
417 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */
419 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */
420 0x01, 0x00, 0x14, 0x00, 0x12,
421 0x00, 0x00 /* End of LLDPDU */
424 lldp_handler_calls
= 0;
425 assert_se(start_lldp(&lldp
, e
, lldp_handler
, NULL
) == 0);
427 assert_se(write(test_fd
[1], frame
, sizeof(frame
)) == sizeof(frame
));
429 assert_se(lldp_handler_calls
== 1);
430 assert_se(sd_lldp_get_packets(lldp
, &packets
) == 1);
432 assert_se(sd_lldp_packet_read_port_vlan_id(packets
[0], &id16
) == 0);
433 assert_se(id16
== 0x1234);
435 assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets
[0], &flags
, &id16
) == 0);
436 assert_se(flags
== 1);
437 assert_se(id16
== 0x7788);
439 assert_se(sd_lldp_packet_read_vlan_name(packets
[0], &id16
, &str
, &len
) == 0);
440 assert_se(id16
== 0x1234);
442 assert_se(strneq(str
, "Vlan51", 6));
444 assert_se(sd_lldp_packet_read_management_vid(packets
[0], &id16
) == 0);
445 assert_se(id16
== 0x0102);
447 assert_se(sd_lldp_packet_read_link_aggregation(packets
[0], &flags
, &id32
) == 0);
448 assert_se(flags
== 1);
449 assert_se(id32
== 0x00140012);
451 sd_lldp_packet_unref(packets
[0]);
454 assert_se(stop_lldp(lldp
) == 0);
457 int main(int argc
, char *argv
[]) {
458 _cleanup_event_unref_ sd_event
*e
= NULL
;
462 /* LLDP reception tests */
463 assert_se(sd_event_new(&e
) == 0);
464 test_receive_basic_packet(e
);
465 test_receive_incomplete_packet(e
);
466 test_receive_oui_packet(e
);