ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani This file is part of systemd.
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani Copyright (C) 2014 Tom Gundersen
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani Copyright (C) 2014 Susant Sahani
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani systemd is free software; you can redistribute it and/or modify it
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani under the terms of the GNU Lesser General Public License as published by
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani the Free Software Foundation; either version 2.1 of the License, or
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani (at your option) any later version.
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani systemd is distributed in the hope that it will be useful, but
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani WITHOUT ANY WARRANTY; without even the implied warranty of
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani Lesser General Public License for more details.
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani You should have received a copy of the GNU Lesser General Public License
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani along with systemd; If not, see <http://www.gnu.org/licenses/>.
176c355b43e616b61552566303ad59d5fd910333Beniamino Galvanitlv_packet *sd_lldp_packet_ref(tlv_packet *m) {
176c355b43e616b61552566303ad59d5fd910333Beniamino Galvanitlv_packet *sd_lldp_packet_unref(tlv_packet *m) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_append_u8(tlv_packet *m, uint8_t data) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani return tlv_packet_append_bytes(m, &data, sizeof(uint8_t));
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_append_u16(tlv_packet *m, uint16_t data) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani return tlv_packet_append_bytes(m, &type, sizeof(uint16_t));
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_append_u32(tlv_packet *m, uint32_t data) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani return tlv_packet_append_bytes(m, &type, sizeof(uint32_t));
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani return tlv_packet_append_bytes(m, data, size);
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint lldp_tlv_packet_close_container(tlv_packet *m) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani memcpy(&type, m->container_pos, sizeof(uint16_t));
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani type |= htons(((m->pdu + m->length) - (m->container_pos + 2)) & 0x01ff);
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani memcpy(m->container_pos, &type, sizeof(uint16_t));
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahanistatic inline int tlv_packet_read_internal(tlv_section *m, void **data) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_read_u8(tlv_packet *m, uint8_t *data) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani r = tlv_packet_read_internal(m->container, &val);
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_read_u16(tlv_packet *m, uint16_t *data) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani r = tlv_packet_read_internal(m->container, &val);
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_read_u32(tlv_packet *m, uint32_t *data) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani r = tlv_packet_read_internal(m->container, &val);
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani r = tlv_packet_read_internal(m->container, &val);
29eca2ff897dfbac65ef401515effb055da65339Beniamino Galvani *data_length = m->container->data + m->container->length - m->container->read_pos;
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani r = tlv_packet_read_internal(m->container, &val);
29eca2ff897dfbac65ef401515effb055da65339Beniamino Galvani *data_length = m->container->data + m->container->length - m->container->read_pos;
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani/* parse raw TLV packet */
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
a8eaaee72a2f06e0fb64fb71de3b71ecba31dafbJan Engelhardt /* extract Ethernet header */
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani p += sizeof(struct ether_header);
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani for (l = 0; l <= size; ) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani if (section->type == LLDP_TYPE_END || section->type >=_LLDP_TYPE_MAX) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahani LIST_INSERT_AFTER(section, m->sections, tail, section);
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) {
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvani assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL);
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvaniint lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) {
ad1ad5c8e36ea795034fcdac660b15d7c141d55bSusant Sahaniint lldp_tlv_packet_exit_container(tlv_packet *m) {
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvanistatic int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t *value) {
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvani r = lldp_tlv_packet_enter_container(tlv, type);
564cabd46c7c1532ad4d562bf8332eaed49ac201Beniamino Galvani return r < 0 ? r : r2;
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvanistatic int lldp_tlv_packet_read_string_tlv(tlv_packet *tlv, uint16_t type, char **data, uint16_t *length) {
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvani r = lldp_tlv_packet_enter_container(tlv, type);
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvani r = tlv_packet_read_string(tlv, &s, length);
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvani *data = (char *) s;
564cabd46c7c1532ad4d562bf8332eaed49ac201Beniamino Galvani return r < 0 ? r : r2;
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvaniint sd_lldp_packet_read_chassis_id(tlv_packet *tlv,
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvani r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID);
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvani r = tlv_packet_read_bytes(tlv, data, length);
564cabd46c7c1532ad4d562bf8332eaed49ac201Beniamino Galvani return r < 0 ? r : r2;
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvaniint sd_lldp_packet_read_port_id(tlv_packet *tlv,
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvani r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID);
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvani r = tlv_packet_read_string(tlv, &s, length);
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvani r = tlv_packet_read_bytes(tlv, data, length);
564cabd46c7c1532ad4d562bf8332eaed49ac201Beniamino Galvani return r < 0 ? r : r2;
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvaniint sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) {
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvani return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_TTL, ttl);
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvaniint sd_lldp_packet_read_system_name(tlv_packet *tlv,
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvani return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_NAME, data, length);
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvaniint sd_lldp_packet_read_system_description(tlv_packet *tlv,
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvani return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION, data, length);
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvaniint sd_lldp_packet_read_port_description(tlv_packet *tlv,
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvani return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_PORT_DESCRIPTION, data, length);
b57003ecc3fe92c8074cbc72ee2b7d9cda742271Beniamino Galvaniint sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) {
11e8357164694d8307dea5bcae017c98c5f125abBeniamino Galvani return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data);
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvaniint sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) {
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvani r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID);
564cabd46c7c1532ad4d562bf8332eaed49ac201Beniamino Galvani return r < 0 ? r : r2;
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvaniint sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) {
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvani r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID);
564cabd46c7c1532ad4d562bf8332eaed49ac201Beniamino Galvani return r < 0 ? r : r2;
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvaniint sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) {
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvani r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME);
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvani r = tlv_packet_read_string(tlv, name, length);
564cabd46c7c1532ad4d562bf8332eaed49ac201Beniamino Galvani return r < 0 ? r : r2;
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvaniint sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) {
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvani r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID);
564cabd46c7c1532ad4d562bf8332eaed49ac201Beniamino Galvani return r < 0 ? r : r2;
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvaniint sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) {
d8c89d6198651e34786bc78df26f313eede9918bBeniamino Galvani r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION);
564cabd46c7c1532ad4d562bf8332eaed49ac201Beniamino Galvani return r < 0 ? r : r2;
4fc6de5df31c81ae35e82ed91d0a2ee515edad41Beniamino Galvaniint sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) {
4fc6de5df31c81ae35e82ed91d0a2ee515edad41Beniamino Galvani /* 802.1AB-2009, Table 7-1 */
4fc6de5df31c81ae35e82ed91d0a2ee515edad41Beniamino Galvani if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN))
4fc6de5df31c81ae35e82ed91d0a2ee515edad41Beniamino Galvani *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE;
4fc6de5df31c81ae35e82ed91d0a2ee515edad41Beniamino Galvani else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN))
4fc6de5df31c81ae35e82ed91d0a2ee515edad41Beniamino Galvani *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE;
4fc6de5df31c81ae35e82ed91d0a2ee515edad41Beniamino Galvani else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN))