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 "alloc-util.h"
32 #include "event-util.h"
34 #include "lldp-network.h"
38 #include "string-util.h"
40 #define TEST_LLDP_PORT "em1"
41 #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
42 #define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
44 static int test_fd
[2];
46 static struct ether_addr mac_addr
= {
47 .ether_addr_octet
= {'A', 'B', 'C', '1', '2', '3'}
50 static int lldp_build_tlv_packet(tlv_packet
**ret
) {
51 _cleanup_lldp_packet_unref_ tlv_packet
*m
= NULL
;
52 const uint8_t lldp_dst
[] = LLDP_MULTICAST_ADDR
;
53 struct ether_header ether
= {
54 .ether_type
= htons(ETHERTYPE_LLDP
),
57 /* Append Ethernet header */
58 memcpy(ðer
.ether_dhost
, lldp_dst
, ETHER_ADDR_LEN
);
59 memcpy(ðer
.ether_shost
, &mac_addr
, ETHER_ADDR_LEN
);
61 assert_se(tlv_packet_new(&m
) >= 0);
63 assert_se(tlv_packet_append_bytes(m
, ðer
, sizeof(struct ether_header
)) >= 0);
65 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_CHASSIS_ID
) >= 0);
67 assert_se(tlv_packet_append_u8(m
, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS
) >= 0);
68 assert_se(tlv_packet_append_bytes(m
, &mac_addr
, ETHER_ADDR_LEN
) >= 0);
70 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
73 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_PORT_ID
) >= 0);
75 assert_se(tlv_packet_append_u8(m
, LLDP_PORT_SUBTYPE_INTERFACE_NAME
) >= 0);
76 assert_se(tlv_packet_append_bytes(m
, TEST_LLDP_PORT
, strlen(TEST_LLDP_PORT
) + 1) >= 0);
78 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
81 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_TTL
) >= 0);
83 assert_se(tlv_packet_append_u16(m
, 170) >= 0);
85 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
88 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_SYSTEM_NAME
) >= 0);
90 assert_se(tlv_packet_append_bytes(m
, TEST_LLDP_TYPE_SYSTEM_NAME
,
91 strlen(TEST_LLDP_TYPE_SYSTEM_NAME
)) >= 0);
92 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
94 /* system descrition */
95 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_SYSTEM_DESCRIPTION
) >= 0);
97 assert_se(tlv_packet_append_bytes(m
, TEST_LLDP_TYPE_SYSTEM_DESC
,
98 strlen(TEST_LLDP_TYPE_SYSTEM_DESC
)) >= 0);
100 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
102 /* Mark end of packet */
103 assert_se(lldp_tlv_packet_open_container(m
, LLDP_TYPE_END
) >= 0);
104 assert_se(lldp_tlv_packet_close_container(m
) >= 0);
113 static int lldp_parse_chassis_tlv(tlv_packet
*m
, uint8_t *type
) {
117 assert_se(lldp_tlv_packet_enter_container(m
, LLDP_TYPE_CHASSIS_ID
) >= 0);
118 assert_se(tlv_packet_read_u8(m
, &subtype
) >= 0);
121 case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS
:
123 *type
= LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS
;
124 assert_se(tlv_packet_read_bytes(m
, &p
, &length
) >= 0);
126 assert_se(memcmp(p
, &mac_addr
.ether_addr_octet
, ETHER_ADDR_LEN
) == 0);
130 assert_not_reached("Unhandled option");
133 assert_se(lldp_tlv_packet_exit_container(m
) >= 0);
138 static int lldp_parse_port_id_tlv(tlv_packet
*m
) {
139 _cleanup_free_
char *p
= NULL
;
144 assert_se(lldp_tlv_packet_enter_container(m
, LLDP_TYPE_PORT_ID
) >= 0);
146 assert_se(tlv_packet_read_u8(m
, &subtype
) >= 0);
149 case LLDP_PORT_SUBTYPE_INTERFACE_NAME
:
150 assert_se(tlv_packet_read_string(m
, &str
, &length
) >= 0);
152 p
= strndup(str
, length
-1);
155 assert_se(streq(p
, TEST_LLDP_PORT
) == 1);
158 assert_not_reached("Unhandled option");
161 assert_se(lldp_tlv_packet_exit_container(m
) >= 0);
166 static int lldp_parse_system_name_tlv(tlv_packet
*m
) {
167 _cleanup_free_
char *p
= NULL
;
171 assert_se(lldp_tlv_packet_enter_container(m
, LLDP_TYPE_SYSTEM_NAME
) >= 0);
172 assert_se(tlv_packet_read_string(m
, &str
, &length
) >= 0);
174 p
= strndup(str
, length
);
177 assert_se(streq(p
, TEST_LLDP_TYPE_SYSTEM_NAME
) == 1);
179 assert_se(lldp_tlv_packet_exit_container(m
) >= 0);
184 static int lldp_parse_system_desc_tlv(tlv_packet
*m
) {
185 _cleanup_free_
char *p
= NULL
;
189 assert_se(lldp_tlv_packet_enter_container(m
, LLDP_TYPE_SYSTEM_DESCRIPTION
) >= 0);
190 assert_se(tlv_packet_read_string(m
, &str
, &length
) >= 0);
192 p
= strndup(str
, length
);
195 assert_se(streq(p
, TEST_LLDP_TYPE_SYSTEM_DESC
) == 1);
197 assert_se(lldp_tlv_packet_exit_container(m
) >= 0);
202 static int lldp_parse_ttl_tlv(tlv_packet
*m
) {
205 assert_se(lldp_tlv_packet_enter_container(m
, LLDP_TYPE_TTL
) >= 0);
206 assert_se(tlv_packet_read_u16(m
, &ttl
) >= 0);
208 assert_se(ttl
== 170);
210 assert_se(lldp_tlv_packet_exit_container(m
) >= 0);
215 static int lldp_get_destination_type(tlv_packet
*m
) {
218 assert_se(sd_lldp_packet_get_destination_type(m
, &dest
) >= 0);
219 assert_se(dest
== SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE
);
224 static int lldp_parse_tlv_packet(tlv_packet
*m
, int len
) {
227 assert_se(tlv_packet_parse_pdu(m
, len
) >= 0);
228 assert_se(lldp_parse_chassis_tlv(m
, &subtype
) >= 0);
229 assert_se(lldp_parse_port_id_tlv(m
) >= 0);
230 assert_se(lldp_parse_system_name_tlv(m
) >= 0);
231 assert_se(lldp_parse_ttl_tlv(m
) >= 0);
232 assert_se(lldp_parse_system_desc_tlv(m
) >= 0);
234 assert_se(lldp_get_destination_type(m
) >= 0);
239 static void test_parser(void) {
240 _cleanup_lldp_packet_unref_ tlv_packet
*tlv
= NULL
;
243 lldp_build_tlv_packet(&tlv
);
244 /* parse the packet */
245 tlv_packet_parse_pdu(tlv
, tlv
->length
);
247 lldp_parse_tlv_packet(tlv
, tlv
->length
);
250 int lldp_network_bind_raw_socket(int ifindex
) {
251 if (socketpair(AF_UNIX
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0, test_fd
) < 0)
257 static int lldp_handler_calls
;
258 static void lldp_handler (sd_lldp
*lldp
, int event
, void *userdata
) {
259 lldp_handler_calls
++;
262 static int start_lldp(sd_lldp
**lldp
, sd_event
*e
, sd_lldp_cb_t cb
, void *cb_data
) {
265 r
= sd_lldp_new(42, "dummy", &mac_addr
, lldp
);
269 r
= sd_lldp_attach_event(*lldp
, e
, 0);
273 r
= sd_lldp_set_callback(*lldp
, cb
, cb_data
);
277 r
= sd_lldp_start(*lldp
);
284 static int stop_lldp(sd_lldp
*lldp
) {
287 r
= sd_lldp_stop(lldp
);
291 r
= sd_lldp_detach_event(lldp
);
296 safe_close(test_fd
[1]);
301 static void test_receive_basic_packet(sd_event
*e
) {
303 sd_lldp_packet
**packets
;
305 uint16_t length
, ttl
;
309 /* Ethernet header */
310 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
311 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
312 0x88, 0xcc, /* Ethertype */
313 /* LLDP mandatory TLVs */
314 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
316 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
317 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
318 /* LLDP optional TLVs */
319 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */
320 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */
321 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */
322 0x00, 0x00 /* End Of LLDPDU */
325 lldp_handler_calls
= 0;
326 assert_se(start_lldp(&lldp
, e
, lldp_handler
, NULL
) == 0);
328 assert_se(write(test_fd
[1], frame
, sizeof(frame
)) == sizeof(frame
));
330 assert_se(lldp_handler_calls
== 1);
331 assert_se(sd_lldp_get_packets(lldp
, &packets
) == 1);
333 assert_se(sd_lldp_packet_read_chassis_id(packets
[0], &type
, &data
, &length
) == 0);
334 assert_se(type
== LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS
);
335 assert_se(length
== ETH_ALEN
);
336 assert_se(!memcmp(data
, "\x00\x01\x02\x03\x04\x05", ETH_ALEN
));
338 assert_se(sd_lldp_packet_read_port_id(packets
[0], &type
, &data
, &length
) == 0);
339 assert_se(type
== LLDP_PORT_SUBTYPE_INTERFACE_NAME
);
340 assert_se(length
== 3);
341 assert_se(strneq((char *) data
, "1/3", 3));
343 assert_se(sd_lldp_packet_read_port_description(packets
[0], &str
, &length
) == 0);
344 assert_se(length
== 4);
345 assert_se(strneq(str
, "Port", 4));
347 assert_se(sd_lldp_packet_read_system_name(packets
[0], &str
, &length
) == 0);
348 assert_se(length
== 3);
349 assert_se(strneq(str
, "SYS", 3));
351 assert_se(sd_lldp_packet_read_system_description(packets
[0], &str
, &length
) == 0);
352 assert_se(length
== 4); /* This is the real length in the TLV packet */
353 assert_se(strneq(str
, "foo", 3));
355 assert_se(sd_lldp_packet_read_ttl(packets
[0], &ttl
) == 0);
356 assert_se(ttl
== 120);
358 assert_se(sd_lldp_packet_get_destination_type(packets
[0], &dest_type
) == 0);
359 assert_se(dest_type
== SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE
);
361 sd_lldp_packet_unref(packets
[0]);
364 assert_se(stop_lldp(lldp
) == 0);
367 static void test_receive_incomplete_packet(sd_event
*e
) {
369 sd_lldp_packet
**packets
;
371 /* Ethernet header */
372 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
373 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
374 0x88, 0xcc, /* Ethertype */
375 /* LLDP mandatory TLVs */
376 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
378 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
380 0x00, 0x00 /* End Of LLDPDU */
383 lldp_handler_calls
= 0;
384 assert_se(start_lldp(&lldp
, e
, lldp_handler
, NULL
) == 0);
386 assert_se(write(test_fd
[1], frame
, sizeof(frame
)) == sizeof(frame
));
388 assert_se(lldp_handler_calls
== 0);
389 assert_se(sd_lldp_get_packets(lldp
, &packets
) == 0);
391 assert_se(stop_lldp(lldp
) == 0);
394 static void test_receive_oui_packet(sd_event
*e
) {
396 sd_lldp_packet
**packets
;
402 /* Ethernet header */
403 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
404 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
405 0x88, 0xcc, /* Ethertype */
406 /* LLDP mandatory TLVs */
407 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
409 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */
410 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
411 /* LLDP optional TLVs */
412 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */
414 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */
416 0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */
417 0x12, 0x34, 0x06, 0x56, 0x6c, 0x61,
419 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */
421 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */
422 0x01, 0x00, 0x14, 0x00, 0x12,
423 0x00, 0x00 /* End of LLDPDU */
426 lldp_handler_calls
= 0;
427 assert_se(start_lldp(&lldp
, e
, lldp_handler
, NULL
) == 0);
429 assert_se(write(test_fd
[1], frame
, sizeof(frame
)) == sizeof(frame
));
431 assert_se(lldp_handler_calls
== 1);
432 assert_se(sd_lldp_get_packets(lldp
, &packets
) == 1);
434 assert_se(sd_lldp_packet_read_port_vlan_id(packets
[0], &id16
) == 0);
435 assert_se(id16
== 0x1234);
437 assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets
[0], &flags
, &id16
) == 0);
438 assert_se(flags
== 1);
439 assert_se(id16
== 0x7788);
441 assert_se(sd_lldp_packet_read_vlan_name(packets
[0], &id16
, &str
, &len
) == 0);
442 assert_se(id16
== 0x1234);
444 assert_se(strneq(str
, "Vlan51", 6));
446 assert_se(sd_lldp_packet_read_management_vid(packets
[0], &id16
) == 0);
447 assert_se(id16
== 0x0102);
449 assert_se(sd_lldp_packet_read_link_aggregation(packets
[0], &flags
, &id32
) == 0);
450 assert_se(flags
== 1);
451 assert_se(id32
== 0x00140012);
453 sd_lldp_packet_unref(packets
[0]);
456 assert_se(stop_lldp(lldp
) == 0);
459 int main(int argc
, char *argv
[]) {
460 _cleanup_event_unref_ sd_event
*e
= NULL
;
464 /* LLDP reception tests */
465 assert_se(sd_event_new(&e
) == 0);
466 test_receive_basic_packet(e
);
467 test_receive_incomplete_packet(e
);
468 test_receive_oui_packet(e
);