Skip to content

Commit 11f7141

Browse files
fredrikdanielmollerhefloryd
authored andcommitted
lldp: Only save received IPv4 address, not IPv6.
Previously, if a received LLDP packet contained multiple Management Address TLVs, only the last one would be saved for later use. In the case that the first TLV was the IPv4 address and a second TLV contained an IPv6 address, the IPv4 address would be discarded. As Profinet uses Ipv4, this was bad. Fixed by only saving the IPv4 address. Unit tests were also added.
1 parent ee517c7 commit 11f7141

File tree

2 files changed

+223
-51
lines changed

2 files changed

+223
-51
lines changed

src/common/pf_lldp.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,20 @@ void pf_lldp_reset_peer_timeout (
538538
}
539539
}
540540

541+
/**
542+
* @internal
543+
* Check if management address is of type IPv4
544+
*
545+
* @param address In: Management address.
546+
* @return true if address is a valid IPv4 address,
547+
* false if not.
548+
*/
549+
static bool pf_lldp_management_address_is_ipv4 (
550+
const pf_lldp_management_address_t * address)
551+
{
552+
return address->is_valid && address->subtype == 1 && address->len == 4;
553+
}
554+
541555
int pf_lldp_get_peer_timestamp (
542556
pnet_t * net,
543557
int loc_port_num,
@@ -1442,6 +1456,7 @@ int pf_lldp_parse_packet (
14421456
lldp_tlv_t tlv;
14431457
pf_lldp_org_header_t org;
14441458
pf_get_info_t parse_info;
1459+
pf_lldp_management_address_t management_address;
14451460
uint16_t offset = 0;
14461461

14471462
memset (lldp_peer_info, 0, sizeof (*lldp_peer_info));
@@ -1490,7 +1505,11 @@ int pf_lldp_parse_packet (
14901505
&parse_info,
14911506
&offset,
14921507
tlv.len,
1493-
&lldp_peer_info->management_address);
1508+
&management_address);
1509+
if (pf_lldp_management_address_is_ipv4 (&management_address))
1510+
{
1511+
lldp_peer_info->management_address = management_address;
1512+
}
14941513
break;
14951514
case LLDP_TYPE_ORG_SPEC:
14961515
{

test/test_lldp.cpp

Lines changed: 203 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -70,73 +70,160 @@ static const char * port_id_test_sample_1 =
7070
"\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x31"
7171
"\x32\x33\x34\x35\x36\x37\x38\x39\x30";
7272

73-
static pf_lldp_peer_info_t fake_peer_info (void)
73+
static pf_lldp_chassis_id_t fake_chassis_id (void)
7474
{
75-
pf_lldp_peer_info_t peer;
76-
77-
memset (&peer, 0, sizeof (peer));
75+
pf_lldp_chassis_id_t chassis_id;
7876

77+
memset (&chassis_id, 0, sizeof (chassis_id));
7978
snprintf (
80-
peer.chassis_id.string,
81-
sizeof (peer.chassis_id.string),
79+
chassis_id.string,
80+
sizeof (chassis_id.string),
8281
"%s",
8382
"Chassis ID received from remote device");
84-
peer.chassis_id.len = strlen (peer.chassis_id.string);
85-
peer.chassis_id.subtype = PF_LLDP_SUBTYPE_LOCALLY_ASSIGNED;
86-
peer.chassis_id.is_valid = true;
83+
chassis_id.len = strlen (chassis_id.string);
84+
chassis_id.subtype = PF_LLDP_SUBTYPE_LOCALLY_ASSIGNED;
85+
chassis_id.is_valid = true;
86+
return chassis_id;
87+
}
8788

89+
static pf_lldp_port_id_t fake_port_id (void)
90+
{
91+
pf_lldp_port_id_t port_id;
92+
93+
memset (&port_id, 0, sizeof (port_id));
8894
snprintf (
89-
peer.port_id.string,
90-
sizeof (peer.port_id.string),
95+
port_id.string,
96+
sizeof (port_id.string),
9197
"%s",
9298
"Port ID received from remote device");
93-
peer.port_id.len = strlen (peer.port_id.string);
94-
peer.port_id.subtype = PF_LLDP_SUBTYPE_LOCALLY_ASSIGNED;
95-
peer.port_id.is_valid = true;
99+
port_id.len = strlen (port_id.string);
100+
port_id.subtype = PF_LLDP_SUBTYPE_LOCALLY_ASSIGNED;
101+
port_id.is_valid = true;
102+
return port_id;
103+
}
96104

97-
peer.ttl = 12345;
105+
static uint16_t fake_ttl (void)
106+
{
107+
return 12345;
108+
}
98109

110+
static pf_lldp_port_description_t fake_port_description (void)
111+
{
112+
pf_lldp_port_description_t port_description;
113+
114+
memset (&port_description, 0, sizeof (port_description));
99115
snprintf (
100-
peer.port_description.string,
101-
sizeof (peer.port_description.string),
116+
port_description.string,
117+
sizeof (port_description.string),
102118
"%s",
103119
"Port Description");
104-
peer.port_description.len = strlen (peer.port_description.string);
105-
peer.port_description.is_valid = true;
106-
107-
peer.management_address.subtype = 1; /* IPv4 */
108-
peer.management_address.value[0] = 192;
109-
peer.management_address.value[1] = 168;
110-
peer.management_address.value[2] = 10;
111-
peer.management_address.value[3] = 102;
112-
peer.management_address.len = 4;
113-
peer.management_address.interface_number.subtype = 2; /* ifIndex */
114-
peer.management_address.interface_number.value = 1;
115-
peer.management_address.is_valid = true;
116-
117-
peer.phy_config.is_autonegotiation_supported = true;
118-
peer.phy_config.is_autonegotiation_enabled = true;
119-
peer.phy_config.autonegotiation_advertised_capabilities =
120+
port_description.len = strlen (port_description.string);
121+
port_description.is_valid = true;
122+
return port_description;
123+
}
124+
125+
static pf_lldp_management_address_t fake_ipv4_management_address (void)
126+
{
127+
pf_lldp_management_address_t management_address;
128+
129+
memset (&management_address, 0, sizeof (management_address));
130+
management_address.subtype = 1; /* IPv4 */
131+
management_address.value[0] = 192;
132+
management_address.value[1] = 168;
133+
management_address.value[2] = 10;
134+
management_address.value[3] = 102;
135+
management_address.len = 4;
136+
management_address.interface_number.subtype = 2; /* ifIndex */
137+
management_address.interface_number.value = 1;
138+
management_address.is_valid = true;
139+
return management_address;
140+
}
141+
142+
static pf_lldp_management_address_t fake_ipv6_management_address (void)
143+
{
144+
pf_lldp_management_address_t management_address;
145+
146+
memset (&management_address, 0, sizeof (management_address));
147+
management_address.subtype = 2; /* IPv6 */
148+
management_address.value[0] = 0x20;
149+
management_address.value[1] = 0x01;
150+
management_address.value[2] = 0x0d;
151+
management_address.value[3] = 0xd8;
152+
management_address.value[4] = 0x85;
153+
management_address.value[5] = 0xa3;
154+
management_address.value[6] = 0x00;
155+
management_address.value[7] = 0x00;
156+
management_address.value[8] = 0x00;
157+
management_address.value[9] = 0x00;
158+
management_address.value[10] = 0x8a;
159+
management_address.value[11] = 0x2e;
160+
management_address.value[12] = 0x03;
161+
management_address.value[13] = 0x70;
162+
management_address.value[14] = 0x73;
163+
management_address.value[15] = 0x34;
164+
management_address.len = 16;
165+
management_address.interface_number.subtype = 2; /* ifIndex */
166+
management_address.interface_number.value = 1;
167+
management_address.is_valid = true;
168+
return management_address;
169+
}
170+
171+
static pf_lldp_link_status_t fake_phy_config (void)
172+
{
173+
pf_lldp_link_status_t phy_config;
174+
175+
memset (&phy_config, 0, sizeof (phy_config));
176+
phy_config.is_autonegotiation_supported = true;
177+
phy_config.is_autonegotiation_enabled = true;
178+
phy_config.autonegotiation_advertised_capabilities =
120179
PNAL_ETH_AUTONEG_CAP_100BaseTX_HALF_DUPLEX |
121180
PNAL_ETH_AUTONEG_CAP_100BaseTX_FULL_DUPLEX;
122-
peer.phy_config.operational_mau_type =
123-
PNAL_ETH_MAU_COPPER_100BaseTX_FULL_DUPLEX;
124-
peer.phy_config.is_valid = true;
125-
126-
peer.mac_address.addr[0] = 0xab;
127-
peer.mac_address.addr[0] = 0xcd;
128-
peer.mac_address.addr[0] = 0xef;
129-
peer.mac_address.addr[0] = 0x01;
130-
peer.mac_address.addr[0] = 0x23;
131-
peer.mac_address.addr[0] = 0x45;
132-
133-
peer.port_delay.cable_delay_local = 1;
134-
peer.port_delay.rx_delay_local = 2;
135-
peer.port_delay.tx_delay_local = 3;
136-
peer.port_delay.rx_delay_remote = 4;
137-
peer.port_delay.tx_delay_remote = 5;
138-
peer.port_delay.is_valid = true;
181+
phy_config.operational_mau_type = PNAL_ETH_MAU_COPPER_100BaseTX_FULL_DUPLEX;
182+
phy_config.is_valid = true;
183+
return phy_config;
184+
}
185+
186+
static pnet_ethaddr_t fake_mac_address (void)
187+
{
188+
pnet_ethaddr_t mac_address;
189+
190+
memset (&mac_address, 0, sizeof (mac_address));
191+
mac_address.addr[0] = 0xab;
192+
mac_address.addr[0] = 0xcd;
193+
mac_address.addr[0] = 0xef;
194+
mac_address.addr[0] = 0x01;
195+
mac_address.addr[0] = 0x23;
196+
mac_address.addr[0] = 0x45;
197+
return mac_address;
198+
}
139199

200+
static pf_lldp_signal_delay_t fake_port_delay (void)
201+
{
202+
pf_lldp_signal_delay_t port_delay;
203+
204+
memset (&port_delay, 0, sizeof (port_delay));
205+
port_delay.cable_delay_local = 1;
206+
port_delay.rx_delay_local = 2;
207+
port_delay.tx_delay_local = 3;
208+
port_delay.rx_delay_remote = 4;
209+
port_delay.tx_delay_remote = 5;
210+
port_delay.is_valid = true;
211+
return port_delay;
212+
}
213+
214+
static pf_lldp_peer_info_t fake_peer_info (void)
215+
{
216+
pf_lldp_peer_info_t peer;
217+
218+
memset (&peer, 0, sizeof (peer));
219+
peer.chassis_id = fake_chassis_id();
220+
peer.port_id = fake_port_id();
221+
peer.ttl = fake_ttl();
222+
peer.port_description = fake_port_description();
223+
peer.management_address = fake_ipv4_management_address();
224+
peer.phy_config = fake_phy_config();
225+
peer.mac_address = fake_mac_address();
226+
peer.port_delay = fake_port_delay();
140227
return peer;
141228
}
142229

@@ -598,6 +685,72 @@ TEST_F (LldpTest, LldpParsePacketWithTooBigManagementAddress)
598685
EXPECT_EQ (actual.management_address.is_valid, false);
599686
}
600687

688+
TEST_F (LldpTest, LldpParsePacketWithMultipleManagementAddresses)
689+
{
690+
uint8_t packet[MAX_ETH_PAYLOAD_SIZE];
691+
int error;
692+
size_t size;
693+
pf_lldp_peer_info_t actual;
694+
const pf_lldp_chassis_id_t chassis_id = fake_chassis_id();
695+
const pf_lldp_port_id_t port_id = fake_port_id();
696+
const uint16_t ttl = fake_ttl();
697+
const pf_lldp_management_address_t ipv4 = fake_ipv4_management_address();
698+
const pf_lldp_management_address_t ipv6 = fake_ipv6_management_address();
699+
700+
/* Construct LLDP packet with IPv4 and IPv6 addresses (in that order) */
701+
memset (packet, 0xff, MAX_ETH_PAYLOAD_SIZE);
702+
size = 0;
703+
size += construct_packet_chassis_id (&packet[size], &chassis_id);
704+
size += construct_packet_port_id (&packet[size], &port_id);
705+
size += construct_packet_ttl (&packet[size], ttl);
706+
size += construct_packet_management_address (&packet[size], &ipv4);
707+
size += construct_packet_management_address (&packet[size], &ipv6);
708+
size += construct_packet_end_marker (&packet[size]);
709+
710+
memset (&actual, 0xff, sizeof (actual));
711+
712+
error = pf_lldp_parse_packet (packet, size, &actual);
713+
714+
/* Note that only the IPv4 address should be saved, as IPv6 addresses are
715+
* of no use for the p-net stack.
716+
*/
717+
EXPECT_EQ (error, 0);
718+
EXPECT_EQ (actual.management_address.is_valid, true);
719+
EXPECT_EQ (actual.management_address.subtype, ipv4.subtype);
720+
EXPECT_EQ (actual.management_address.len, 4u);
721+
}
722+
723+
TEST_F (LldpTest, LldpParsePacketWithInvalidManagementAddresses)
724+
{
725+
uint8_t packet[MAX_ETH_PAYLOAD_SIZE];
726+
int error;
727+
size_t size;
728+
pf_lldp_peer_info_t actual;
729+
const pf_lldp_chassis_id_t chassis_id = fake_chassis_id();
730+
const pf_lldp_port_id_t port_id = fake_port_id();
731+
const uint16_t ttl = fake_ttl();
732+
pf_lldp_management_address_t address;
733+
734+
address = fake_ipv4_management_address();
735+
address.len = 5;
736+
737+
/* Construct LLDP packet */
738+
memset (packet, 0xff, MAX_ETH_PAYLOAD_SIZE);
739+
size = 0;
740+
size += construct_packet_chassis_id (&packet[size], &chassis_id);
741+
size += construct_packet_port_id (&packet[size], &port_id);
742+
size += construct_packet_ttl (&packet[size], ttl);
743+
size += construct_packet_management_address (&packet[size], &address);
744+
size += construct_packet_end_marker (&packet[size]);
745+
746+
memset (&actual, 0xff, sizeof (actual));
747+
748+
error = pf_lldp_parse_packet (packet, size, &actual);
749+
750+
EXPECT_EQ (error, 0);
751+
EXPECT_EQ (actual.management_address.is_valid, false);
752+
}
753+
601754
TEST_F (LldpTest, LldpGetChassisId)
602755
{
603756
pf_lldp_chassis_id_t chassis_id;

0 commit comments

Comments
 (0)