LCOV - code coverage report
Current view: top level - lib/lldp - lldp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 220 306 71.9 %
Date: 2016-09-14 01:02:56 Functions: 8 11 72.7 %
Branches: 59 175 33.7 %

           Branch data     Line data    Source code
       1                 :            : /* -*- mode: c; c-file-style: "openbsd" -*- */
       2                 :            : /*
       3                 :            :  * Copyright (c) 2015 Nicira, Inc.
       4                 :            :  * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
       5                 :            :  * Copyright (c) 2014 Michael Chapman
       6                 :            :  *
       7                 :            :  * Permission to use, copy, modify, and/or distribute this software for any
       8                 :            :  * purpose with or without fee is hereby granted, provided that the above
       9                 :            :  * copyright notice and this permission notice appear in all copies.
      10                 :            :  *
      11                 :            :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12                 :            :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13                 :            :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14                 :            :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15                 :            :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16                 :            :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17                 :            :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18                 :            :  */
      19                 :            : 
      20                 :            : #include <config.h>
      21                 :            : #include "lldpd.h"
      22                 :            : #include <errno.h>
      23                 :            : #include <time.h>
      24                 :            : #include <unistd.h>
      25                 :            : #include <sys/ioctl.h>
      26                 :            : #include <sys/socket.h>
      27                 :            : #include <sys/types.h>
      28                 :            : #include "compiler.h"
      29                 :            : #include "dp-packet.h"
      30                 :            : #include "packets.h"
      31                 :            : 
      32                 :       2462 : VLOG_DEFINE_THIS_MODULE(lldp);
      33                 :            : 
      34                 :            : /* This set of macro are used to parse packets. The current position in buffer
      35                 :            :  * is `pos'. The length of the remaining space in buffer is `length'.  There is
      36                 :            :  * no check on boundaries.
      37                 :            :  */
      38                 :            : 
      39                 :            : #define PEEK(type, func)                  \
      40                 :            :     (                                     \
      41                 :            :         memcpy(&type, pos, sizeof type), \
      42                 :            :         length -= sizeof type,           \
      43                 :            :         pos += sizeof type,              \
      44                 :            :         func(type)                        \
      45                 :            :     )
      46                 :            : #define PEEK_UINT8 PEEK(types.f_uint8, )
      47                 :            : #define PEEK_UINT16 PEEK(types.f_uint16, ntohs)
      48                 :            : #define PEEK_UINT32 PEEK(types.f_uint32, ntohl)
      49                 :            : #define PEEK_BYTES(value, bytes)   \
      50                 :            :     do {                           \
      51                 :            :         memcpy(value, pos, bytes); \
      52                 :            :         length -= (bytes);         \
      53                 :            :         pos += (bytes);            \
      54                 :            :     } while (0)
      55                 :            : #define PEEK_DISCARD(bytes) \
      56                 :            :     do {                    \
      57                 :            :         length -= (bytes);  \
      58                 :            :         pos += (bytes);     \
      59                 :            :     } while (0)
      60                 :            : #define PEEK_DISCARD_UINT8 PEEK_DISCARD(1)
      61                 :            : #define PEEK_DISCARD_UINT16 PEEK_DISCARD(2)
      62                 :            : #define PEEK_DISCARD_UINT32 PEEK_DISCARD(3)
      63                 :            : #define PEEK_CMP(value, bytes) \
      64                 :            :      (length -= (bytes),       \
      65                 :            :      pos += (bytes),           \
      66                 :            :      memcmp(pos-bytes, value, bytes))
      67                 :            : #define CHECK_TLV_SIZE(x, name)                             \
      68                 :            :     do {                                                    \
      69                 :            :         if (tlv_size < (x)) {                               \
      70                 :            :             VLOG_WARN(name " TLV too short received on %s", \
      71                 :            :                       hardware->h_ifname);                  \
      72                 :            :             goto malformed;                                 \
      73                 :            :         }                                                   \
      74                 :            :     } while (0)
      75                 :            : #define PEEK_SAVE(where) (where = pos, 1)
      76                 :            : 
      77                 :            : static union {
      78                 :            :     uint8_t  f_uint8;
      79                 :            :     ovs_be16 f_uint16;
      80                 :            :     ovs_be32 f_uint32;
      81                 :            : } types;
      82                 :            : 
      83                 :            : static int
      84                 :          0 : lldpd_af_to_lldp_proto(int af)
      85                 :            : {
      86      [ #  #  # ]:          0 :     switch (af) {
      87                 :            :     case LLDPD_AF_IPV4:
      88                 :          0 :         return LLDP_MGMT_ADDR_IP4;
      89                 :            :     case LLDPD_AF_IPV6:
      90                 :          0 :         return LLDP_MGMT_ADDR_IP6;
      91                 :            :     default:
      92                 :          0 :         return LLDP_MGMT_ADDR_NONE;
      93                 :            :     }
      94                 :            : }
      95                 :            : 
      96                 :            : static int
      97                 :          0 : lldpd_af_from_lldp_proto(int proto)
      98                 :            : {
      99      [ #  #  # ]:          0 :     switch (proto) {
     100                 :            :     case LLDP_MGMT_ADDR_IP4:
     101                 :          0 :         return LLDPD_AF_IPV4;
     102                 :            :     case LLDP_MGMT_ADDR_IP6:
     103                 :          0 :         return LLDPD_AF_IPV6;
     104                 :            :     default:
     105                 :          0 :         return LLDPD_AF_UNSPEC;
     106                 :            :     }
     107                 :            : }
     108                 :            : 
     109                 :            : static void
     110                 :          6 : lldp_tlv_put_u8(struct dp_packet *p, uint8_t x)
     111                 :            : {
     112                 :          6 :     dp_packet_put(p, &x, sizeof x);
     113                 :          6 : }
     114                 :            : 
     115                 :            : static void
     116                 :         17 : lldp_tlv_put_u16(struct dp_packet *p, uint16_t x)
     117                 :            : {
     118                 :         17 :     ovs_be16 nx = htons(x);
     119                 :         17 :     dp_packet_put(p, &nx, sizeof nx);
     120                 :         17 : }
     121                 :            : 
     122                 :            : static void
     123                 :          0 : lldp_tlv_put_u32(struct dp_packet *p, uint32_t x)
     124                 :            : {
     125                 :          0 :     ovs_be32 nx = htonl(x);
     126                 :          0 :     dp_packet_put(p, &nx, sizeof nx);
     127                 :          0 : }
     128                 :            : 
     129                 :            : static void
     130                 :          2 : lldp_tlv_put_isid(struct dp_packet *p, uint32_t isid)
     131                 :            : {
     132                 :          2 :     uint8_t *data = dp_packet_put_uninit(p, 3);
     133                 :          2 :     data[0] = isid >> 16;
     134                 :          2 :     data[1] = isid >> 8;
     135                 :          2 :     data[2] = isid;
     136                 :          2 : }
     137                 :            : 
     138                 :            : static void
     139                 :         10 : lldp_tlv_start(struct dp_packet *p, uint8_t tlv, unsigned int *start)
     140                 :            : {
     141                 :         10 :     *start = dp_packet_size(p);
     142                 :         10 :     lldp_tlv_put_u16(p, tlv << 9);
     143                 :         10 : }
     144                 :            : 
     145                 :            : static void
     146                 :         10 : lldp_tlv_end(struct dp_packet *p, unsigned int start)
     147                 :            : {
     148                 :         10 :     ovs_be16 *tlv = dp_packet_at_assert(p, start, 2);
     149                 :         10 :     *tlv |= htons((dp_packet_size(p) - (start + 2)) & 0x1ff);
     150                 :         10 : }
     151                 :            : 
     152                 :            : int
     153                 :          1 : lldp_send(struct lldpd *global OVS_UNUSED,
     154                 :            :           struct lldpd_hardware *hardware,
     155                 :            :           struct dp_packet *p)
     156                 :            : {
     157                 :          1 :     unsigned int orig_size = dp_packet_size(p);
     158                 :            :     unsigned int start;
     159                 :            : 
     160                 :            :     struct lldpd_port *port;
     161                 :            :     struct lldpd_chassis *chassis;
     162                 :            :     struct lldpd_mgmt *mgmt;
     163                 :          1 :     const uint8_t avaya[] = LLDP_TLV_ORG_AVAYA;
     164                 :            :     struct lldpd_aa_isid_vlan_maps_tlv *vlan_isid_map;
     165                 :            :     uint8_t msg_auth_digest[LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH];
     166                 :            : 
     167                 :          1 :     port = &hardware->h_lport;
     168                 :          1 :     chassis = port->p_chassis;
     169                 :            : 
     170                 :            :     /* The ethernet header is filled in elsewhere, we must save room for it. */
     171         [ -  + ]:          1 :     VLOG_DBG("LLDP PDU send to %s mtu %d incoming",
     172                 :            :               hardware->h_ifname, hardware->h_mtu);
     173                 :            : 
     174                 :            :     /* Chassis ID */
     175                 :          1 :     lldp_tlv_start(p, LLDP_TLV_CHASSIS_ID, &start);
     176                 :          1 :     lldp_tlv_put_u8(p, chassis->c_id_subtype);
     177                 :          1 :     dp_packet_put(p, chassis->c_id, chassis->c_id_len);
     178                 :          1 :     lldp_tlv_end(p, start);
     179                 :            : 
     180                 :            :     /* Port ID */
     181                 :          1 :     lldp_tlv_start(p, LLDP_TLV_PORT_ID, &start);
     182                 :          1 :     lldp_tlv_put_u8(p, port->p_id_subtype);
     183                 :          1 :     dp_packet_put(p, port->p_id, port->p_id_len);
     184                 :          1 :     lldp_tlv_end(p, start);
     185                 :            : 
     186                 :            :     /* Time to live */
     187                 :          1 :     lldp_tlv_start(p, LLDP_TLV_TTL, &start);
     188                 :          1 :     lldp_tlv_put_u16(p, chassis->c_ttl);
     189                 :          1 :     lldp_tlv_end(p, start);
     190                 :            : 
     191                 :            :     /* System name */
     192 [ +  - ][ +  - ]:          1 :     if (chassis->c_name && *chassis->c_name != '\0') {
     193                 :          1 :         lldp_tlv_start(p, LLDP_TLV_SYSTEM_NAME, &start);
     194                 :          1 :         dp_packet_put(p, chassis->c_name, strlen(chassis->c_name));
     195                 :          1 :         lldp_tlv_end(p, start);
     196                 :            :     }
     197                 :            : 
     198                 :            :     /* System description (skip it if empty) */
     199 [ +  - ][ +  - ]:          1 :     if (chassis->c_descr && *chassis->c_descr != '\0') {
     200                 :          1 :         lldp_tlv_start(p, LLDP_TLV_SYSTEM_DESCR, &start);
     201                 :          1 :         dp_packet_put(p, chassis->c_descr, strlen(chassis->c_descr));
     202                 :          1 :         lldp_tlv_end(p, start);
     203                 :            :     }
     204                 :            : 
     205                 :            :     /* System capabilities */
     206                 :          1 :     lldp_tlv_start(p, LLDP_TLV_SYSTEM_CAP, &start);
     207                 :          1 :     lldp_tlv_put_u16(p, chassis->c_cap_available);
     208                 :          1 :     lldp_tlv_put_u16(p, chassis->c_cap_enabled);
     209                 :          1 :     lldp_tlv_end(p, start);
     210                 :            : 
     211         [ -  + ]:          1 :     LIST_FOR_EACH (mgmt, m_entries, &chassis->c_mgmt) {
     212                 :          0 :         lldp_tlv_start(p, LLDP_TLV_MGMT_ADDR, &start);
     213                 :          0 :         lldp_tlv_put_u8(p, mgmt->m_addrsize + 1);
     214                 :          0 :         lldp_tlv_put_u8(p, lldpd_af_to_lldp_proto(mgmt->m_family));
     215                 :          0 :         dp_packet_put(p, &mgmt->m_addr, mgmt->m_addrsize);
     216                 :            : 
     217                 :            :         /* Interface port type, OID */
     218         [ #  # ]:          0 :         if (mgmt->m_iface == 0) {
     219                 :            :             /* We don't know the management interface */
     220                 :          0 :             lldp_tlv_put_u8(p, LLDP_MGMT_IFACE_UNKNOWN);
     221                 :          0 :             lldp_tlv_put_u32(p, 0);
     222                 :            :         } else {
     223                 :            :             /* We have the index of the management interface */
     224                 :          0 :             lldp_tlv_put_u8(p, LLDP_MGMT_IFACE_IFINDEX);
     225                 :          0 :             lldp_tlv_put_u32(p, mgmt->m_iface);
     226                 :            :         }
     227                 :          0 :         lldp_tlv_put_u8(p, 0);
     228                 :          0 :         lldp_tlv_end(p, start);
     229                 :            :     }
     230                 :            : 
     231                 :            :     /* Port description */
     232 [ +  - ][ +  - ]:          1 :     if (port->p_descr && *port->p_descr != '\0') {
     233                 :          1 :         lldp_tlv_start(p, LLDP_TLV_PORT_DESCR, &start);
     234                 :          1 :         dp_packet_put(p, port->p_descr, strlen(port->p_descr));
     235                 :          1 :         lldp_tlv_end(p, start);
     236                 :            :     }
     237                 :            : 
     238                 :            :     /* Add Auto Attach tlvs V3.1 to packet. LLDP FA element v3.1 format:
     239                 :            :     TLV Type[127]   TLV Length[50 octets] Avaya OUI[00-04-0D] Subtype[11]
     240                 :            :     7 bits                9 bits                3 octets      1 octet
     241                 :            :     HMAC-SHA Digest  Element Type   State   Mgmt VLAN   Rsvd    System ID
     242                 :            :       32 octets       6 bits        6 bits   12 bits    1 octet 10 octets
     243                 :            :     */
     244                 :            :     /* AA-ELEMENT */
     245         [ +  - ]:          1 :     if (port->p_element.type != 0) {
     246                 :          1 :         u_int16_t aa_element_first_word = 0;
     247                 :          1 :         u_int16_t aa_element_second_word = 0;
     248                 :          1 :         u_int16_t aa_element_state = 0;
     249                 :            :         u_int8_t aa_elem_sys_id_first_byte;
     250                 :            :         u_int8_t aa_elem_sys_id_second_byte;
     251                 :            : 
     252                 :            :         /* Link VLAN Tagging Requirements (bit 1),
     253                 :            :          * Automatic Provisioning Mode (bit 2/3) (left to right, 1 based) */
     254                 :          2 :         aa_element_state = ((port->p_element.vlan_tagging & 0x1) << 5) |
     255                 :          1 :             ((port->p_element.auto_prov_mode & 0x3) << 3);
     256                 :            : 
     257                 :            :         /* Element first word should be first 6 most significant bits of
     258                 :            :          * element type, bitwise OR that with the next 6 bits of the state,
     259                 :            :          * bitwise OR with the first 4 bits of mgmt vlan id.
     260                 :            :          * Element type should be LLDP_TLV_AA_ELEM_TYPE_VIRTUAL_SWITCH for
     261                 :            :          * AA client */
     262                 :          3 :         aa_element_first_word = (port->p_element.type << 10) |
     263                 :          1 :             (aa_element_state << 4) |
     264                 :          1 :             ((port->p_element.mgmt_vlan & 0x0F00)>> 8);
     265                 :            : 
     266                 :            :         /* Element second type should be the first 8 most significant bits
     267                 :            :          * of the remaining 8 bits of mgmt vlan id. */
     268                 :          1 :         aa_element_second_word = (port->p_element.mgmt_vlan & 0xFF) << 8;
     269                 :            : 
     270                 :            :         /* System id first byte should be first 3 most significant bits of
     271                 :            :          * connecion type, bitwise OR that with the device state and bitwise
     272                 :            :          * OR that with the first 2 most significant bitsof rsvd (10 bits). */
     273                 :          2 :         aa_elem_sys_id_first_byte =
     274                 :          1 :             ((port->p_element.system_id.conn_type & 0x7) << 5) |
     275                 :          1 :             ((port->p_element.system_id.rsvd >> 8) & 0x3);
     276                 :            : 
     277                 :            :         /* Second byte should just be the remaining 8 bits of 10 bits rsvd */
     278                 :          1 :         aa_elem_sys_id_second_byte =
     279                 :          1 :             (port->p_element.system_id.rsvd & 0xFF);
     280                 :            : 
     281                 :          1 :         memset(msg_auth_digest, 0, sizeof msg_auth_digest);
     282                 :            : 
     283                 :          1 :         lldp_tlv_start(p, LLDP_TLV_ORG, &start);
     284                 :          1 :         dp_packet_put(p, avaya, sizeof avaya);
     285                 :          1 :         lldp_tlv_put_u8(p, LLDP_TLV_AA_ELEMENT_SUBTYPE);
     286                 :          1 :         dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest);
     287                 :          1 :         lldp_tlv_put_u16(p, aa_element_first_word);
     288                 :          1 :         lldp_tlv_put_u16(p, aa_element_second_word);
     289                 :          1 :         dp_packet_put(p, &port->p_element.system_id.system_mac,
     290                 :            :                       sizeof port->p_element.system_id.system_mac);
     291                 :          1 :         lldp_tlv_put_u8(p, aa_elem_sys_id_first_byte);
     292                 :          1 :         lldp_tlv_put_u8(p, aa_elem_sys_id_second_byte);
     293                 :          1 :         dp_packet_put(p, &port->p_element.system_id.rsvd2,
     294                 :            :                       sizeof port->p_element.system_id.rsvd2);
     295                 :          1 :         lldp_tlv_end(p, start);
     296                 :            :     }
     297                 :            : 
     298         [ +  - ]:          1 :     if (!ovs_list_is_empty(&port->p_isid_vlan_maps)) {
     299                 :            : 
     300                 :          1 :         memset(msg_auth_digest, 0, sizeof msg_auth_digest);
     301                 :            : 
     302                 :          1 :         lldp_tlv_start(p, LLDP_TLV_ORG, &start);
     303                 :          1 :         dp_packet_put(p, avaya, sizeof avaya);
     304                 :          1 :         lldp_tlv_put_u8(p, LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE);
     305                 :          1 :         dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest);
     306                 :            : 
     307         [ +  + ]:          3 :         LIST_FOR_EACH (vlan_isid_map,
     308                 :            :                        m_entries,
     309                 :            :                        &hardware->h_lport.p_isid_vlan_maps) {
     310                 :            :             u_int16_t status_vlan_word;
     311                 :          4 :             status_vlan_word =
     312                 :          2 :                 (vlan_isid_map->isid_vlan_data.status << 12) |
     313                 :          2 :                 vlan_isid_map->isid_vlan_data.vlan;
     314                 :            : 
     315                 :          2 :             lldp_tlv_put_u16(p, status_vlan_word);
     316                 :          2 :             lldp_tlv_put_isid(p, vlan_isid_map->isid_vlan_data.isid);
     317                 :            :         }
     318                 :            : 
     319                 :          1 :         lldp_tlv_end(p, start);
     320                 :            :     }
     321                 :            : 
     322                 :            :     /* END */
     323                 :          1 :     lldp_tlv_start(p, LLDP_TLV_END, &start);
     324                 :          1 :     lldp_tlv_end(p, start);
     325                 :            : 
     326                 :          1 :     hardware->h_tx_cnt++;
     327                 :            : 
     328                 :          1 :     const char *lldp = dp_packet_at_assert(p, orig_size, 0);
     329                 :          1 :     unsigned int lldp_len = dp_packet_size(p) - orig_size;
     330         [ -  + ]:          1 :     if (!hardware->h_lport.p_lastframe
     331         [ #  # ]:          0 :         || hardware->h_lport.p_lastframe->size != lldp_len
     332         [ #  # ]:          0 :         || memcmp(hardware->h_lport.p_lastframe->frame, lldp, lldp_len)) {
     333                 :            : 
     334                 :          1 :         struct lldpd_frame *frame = xmalloc(sizeof *frame + lldp_len);
     335                 :          1 :         frame->size = lldp_len;
     336                 :          1 :         memcpy(frame->frame, lldp, lldp_len);
     337                 :          1 :         free(hardware->h_lport.p_lastframe);
     338                 :          1 :         hardware->h_lport.p_lastframe = frame;
     339                 :          1 :         hardware->h_lport.p_lastchange = time(NULL);
     340                 :            :     }
     341                 :            : 
     342                 :          1 :     return dp_packet_size(p);
     343                 :            : }
     344                 :            : 
     345                 :            : int
     346                 :          1 : lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
     347                 :            :             struct lldpd_hardware *hardware, struct lldpd_chassis **newchassis,
     348                 :            :             struct lldpd_port **newport)
     349                 :            : {
     350                 :            :     struct lldpd_chassis *chassis;
     351                 :            :     struct lldpd_port *port;
     352                 :          1 :     const struct eth_addr lldpaddr = LLDP_MULTICAST_ADDR;
     353                 :          1 :     const char dot1[] = LLDP_TLV_ORG_DOT1;
     354                 :          1 :     const char dot3[] = LLDP_TLV_ORG_DOT3;
     355                 :          1 :     const char med[] = LLDP_TLV_ORG_MED;
     356                 :          1 :     const char avaya_oid[] = LLDP_TLV_ORG_AVAYA;
     357                 :          1 :     const char dcbx[] = LLDP_TLV_ORG_DCBX;
     358                 :            :     char orgid[3];
     359                 :            :     int length, af;
     360                 :          1 :     bool gotend = false;
     361                 :          1 :     bool ttl_received = false;
     362                 :            :     int tlv_size, tlv_type, tlv_subtype;
     363                 :            :     u_int8_t *pos, *tlv;
     364                 :            :     void *b;
     365                 :          1 :     struct lldpd_aa_isid_vlan_maps_tlv *isid_vlan_map = NULL;
     366                 :            :     u_int8_t msg_auth_digest[LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH];
     367                 :            :     struct lldpd_mgmt *mgmt;
     368                 :            :     u_int8_t addr_str_length, addr_str_buffer[32];
     369                 :            :     u_int8_t addr_family, addr_length, *addr_ptr, iface_subtype;
     370                 :            :     u_int32_t iface_number, iface;
     371                 :            : 
     372         [ -  + ]:          1 :     VLOG_DBG("receive LLDP PDU on %s", hardware->h_ifname);
     373                 :            : 
     374                 :          1 :     chassis = xzalloc(sizeof *chassis);
     375                 :          1 :     ovs_list_init(&chassis->c_mgmt);
     376                 :            : 
     377                 :          1 :     port = xzalloc(sizeof *port);
     378                 :          1 :     ovs_list_init(&port->p_isid_vlan_maps);
     379                 :            : 
     380                 :          1 :     length = s;
     381                 :          1 :     pos = (u_int8_t*) frame;
     382                 :            : 
     383         [ -  + ]:          1 :     if (length < 2 * ETH_ADDR_LEN + sizeof(u_int16_t)) {
     384         [ #  # ]:          0 :         VLOG_WARN("too short frame received on %s", hardware->h_ifname);
     385                 :          0 :         goto malformed;
     386                 :            :     }
     387         [ -  + ]:          1 :     if (PEEK_CMP(&lldpaddr, ETH_ADDR_LEN) != 0) {
     388         [ #  # ]:          0 :         VLOG_INFO("frame not targeted at LLDP multicast address "
     389                 :            :                   "received on %s", hardware->h_ifname);
     390                 :          0 :         goto malformed;
     391                 :            :     }
     392                 :            : 
     393                 :          1 :     PEEK_DISCARD(ETH_ADDR_LEN); /* Skip source address */
     394         [ -  + ]:          1 :     if (PEEK_UINT16 != ETHERTYPE_LLDP) {
     395         [ #  # ]:          0 :         VLOG_INFO("non LLDP frame received on %s", hardware->h_ifname);
     396                 :          0 :         goto malformed;
     397                 :            :     }
     398                 :            : 
     399 [ +  + ][ +  - ]:         11 :     while (length && !gotend) {
     400         [ -  + ]:         10 :         if (length < 2) {
     401         [ #  # ]:          0 :             VLOG_WARN("tlv header too short received on %s",
     402                 :            :                       hardware->h_ifname);
     403                 :          0 :             goto malformed;
     404                 :            :         }
     405                 :         10 :         tlv_size = PEEK_UINT16;
     406                 :         10 :         tlv_type = tlv_size >> 9;
     407                 :         10 :         tlv_size = tlv_size & 0x1ff;
     408                 :         10 :         (void) PEEK_SAVE(tlv);
     409         [ -  + ]:         10 :         if (length < tlv_size) {
     410         [ #  # ]:          0 :             VLOG_WARN("frame too short for tlv received on %s",
     411                 :            :                       hardware->h_ifname);
     412                 :          0 :             goto malformed;
     413                 :            :         }
     414                 :            : 
     415   [ +  +  +  +  :         10 :         switch (tlv_type) {
             +  -  +  - ]
     416                 :            :         case LLDP_TLV_END:
     417         [ -  + ]:          1 :             if (tlv_size != 0) {
     418         [ #  # ]:          0 :                 VLOG_WARN("lldp end received with size not null on %s",
     419                 :            :                           hardware->h_ifname);
     420                 :          0 :                 goto malformed;
     421                 :            :             }
     422         [ -  + ]:          1 :             if (length) {
     423         [ #  # ]:          0 :                 VLOG_DBG("extra data after lldp end on %s",
     424                 :            :                          hardware->h_ifname);
     425                 :            :             }
     426                 :          1 :             gotend = true;
     427                 :          1 :             break;
     428                 :            : 
     429                 :            :         case LLDP_TLV_CHASSIS_ID:
     430                 :            :         case LLDP_TLV_PORT_ID:
     431 [ -  + ][ #  # ]:          2 :             CHECK_TLV_SIZE(2, "Port Id");
     432                 :          2 :             tlv_subtype = PEEK_UINT8;
     433 [ +  - ][ -  + ]:          2 :             if (tlv_subtype == 0 || tlv_subtype > 7) {
     434         [ #  # ]:          0 :                 VLOG_WARN("unknown subtype for tlv id received on %s",
     435                 :            :                           hardware->h_ifname);
     436                 :          0 :                 goto malformed;
     437                 :            :             }
     438                 :          2 :             b = xzalloc(tlv_size - 1);
     439                 :          2 :             PEEK_BYTES(b, tlv_size - 1);
     440         [ +  + ]:          2 :             if (tlv_type == LLDP_TLV_PORT_ID) {
     441                 :          1 :                 port->p_id_subtype = tlv_subtype;
     442                 :          1 :                 port->p_id = b;
     443                 :          1 :                 port->p_id_len = tlv_size - 1;
     444                 :            :             } else {
     445                 :          1 :                 chassis->c_id_subtype = tlv_subtype;
     446                 :          1 :                 chassis->c_id = b;
     447                 :          1 :                 chassis->c_id_len = tlv_size - 1;
     448                 :            :             }
     449                 :          2 :             break;
     450                 :            : 
     451                 :            :         case LLDP_TLV_TTL:
     452 [ -  + ][ #  # ]:          1 :             CHECK_TLV_SIZE(2, "TTL");
     453                 :          1 :             chassis->c_ttl = PEEK_UINT16;
     454                 :          1 :             ttl_received = true;
     455                 :          1 :             break;
     456                 :            : 
     457                 :            :         case LLDP_TLV_PORT_DESCR:
     458                 :            :         case LLDP_TLV_SYSTEM_NAME:
     459                 :            :         case LLDP_TLV_SYSTEM_DESCR:
     460         [ -  + ]:          3 :             if (tlv_size < 1) {
     461         [ #  # ]:          0 :                 VLOG_DBG("empty tlv received on %s", hardware->h_ifname);
     462                 :          0 :                 break;
     463                 :            :             }
     464                 :          3 :             b = xzalloc(tlv_size + 1);
     465                 :          3 :             PEEK_BYTES(b, tlv_size);
     466         [ +  + ]:          3 :             if (tlv_type == LLDP_TLV_PORT_DESCR) {
     467                 :          1 :                 port->p_descr = b;
     468         [ +  + ]:          2 :             } else if (tlv_type == LLDP_TLV_SYSTEM_NAME) {
     469                 :          1 :                 chassis->c_name = b;
     470                 :            :             } else {
     471                 :          1 :                 chassis->c_descr = b;
     472                 :            :             }
     473                 :          3 :             break;
     474                 :            : 
     475                 :            :         case LLDP_TLV_SYSTEM_CAP:
     476 [ -  + ][ #  # ]:          1 :             CHECK_TLV_SIZE(4, "System capabilities");
     477                 :          1 :             chassis->c_cap_available = PEEK_UINT16;
     478                 :          1 :             chassis->c_cap_enabled = PEEK_UINT16;
     479                 :          1 :             break;
     480                 :            : 
     481                 :            :         case LLDP_TLV_MGMT_ADDR:
     482 [ #  # ][ #  # ]:          0 :             CHECK_TLV_SIZE(1, "Management address");
     483                 :          0 :             addr_str_length = PEEK_UINT8;
     484 [ #  # ][ #  # ]:          0 :             CHECK_TLV_SIZE(1 + addr_str_length, "Management address");
     485                 :          0 :             PEEK_BYTES(addr_str_buffer, addr_str_length);
     486                 :          0 :             addr_length = addr_str_length - 1;
     487                 :          0 :             addr_family = addr_str_buffer[0];
     488                 :          0 :             addr_ptr = &addr_str_buffer[1];
     489 [ #  # ][ #  # ]:          0 :             CHECK_TLV_SIZE(1 + addr_str_length + 5, "Management address");
     490                 :          0 :             iface_subtype = PEEK_UINT8;
     491                 :          0 :             iface_number = PEEK_UINT32;
     492                 :            : 
     493                 :          0 :             af = lldpd_af_from_lldp_proto(addr_family);
     494         [ #  # ]:          0 :             if (af == LLDPD_AF_UNSPEC) {
     495                 :          0 :                 break;
     496                 :            :             }
     497                 :          0 :             iface = iface_subtype == LLDP_MGMT_IFACE_IFINDEX ?
     498         [ #  # ]:          0 :                 iface_number : 0;
     499                 :          0 :             mgmt = lldpd_alloc_mgmt(af, addr_ptr, addr_length, iface);
     500         [ #  # ]:          0 :             if (mgmt == NULL) {
     501         [ #  # ]:          0 :                 VLOG_WARN("unable to allocate memory for management address");
     502                 :          0 :                 goto malformed;
     503                 :            :             }
     504                 :          0 :             ovs_list_push_back(&chassis->c_mgmt, &mgmt->m_entries);
     505                 :          0 :             break;
     506                 :            : 
     507                 :            :         case LLDP_TLV_ORG:
     508 [ -  + ][ #  # ]:          2 :             CHECK_TLV_SIZE(4, "Organisational");
     509                 :          2 :             PEEK_BYTES(orgid, sizeof orgid);
     510                 :          2 :             tlv_subtype = PEEK_UINT8;
     511         [ -  + ]:          2 :             if (memcmp(dot1, orgid, sizeof orgid) == 0) {
     512                 :          0 :                 hardware->h_rx_unrecognized_cnt++;
     513         [ -  + ]:          2 :             } else if (memcmp(dot3, orgid, sizeof orgid) == 0) {
     514                 :          0 :                 hardware->h_rx_unrecognized_cnt++;
     515         [ -  + ]:          2 :             } else if (memcmp(med, orgid, sizeof orgid) == 0) {
     516                 :            :                 /* LLDP-MED */
     517                 :          0 :                 hardware->h_rx_unrecognized_cnt++;
     518         [ +  - ]:          2 :             } else if (memcmp(avaya_oid, orgid, sizeof orgid) == 0) {
     519                 :            :                 u_int32_t aa_element_dword;
     520                 :            :                 u_int16_t aa_system_id_word;
     521                 :            :                 u_int16_t aa_status_vlan_word;
     522                 :            :                 u_int8_t aa_element_state;
     523                 :            :                 unsigned short num_mappings;
     524                 :            : 
     525      [ +  +  - ]:          2 :                 switch(tlv_subtype) {
     526                 :            :                 case LLDP_TLV_AA_ELEMENT_SUBTYPE:
     527                 :          1 :                     PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest);
     528                 :            : 
     529                 :          1 :                     aa_element_dword = PEEK_UINT32;
     530                 :            : 
     531                 :            :                     /* Type is first 6 most-significant bits of
     532                 :            :                      * aa_element_dword */
     533                 :          1 :                     port->p_element.type = aa_element_dword >> 26;
     534                 :            : 
     535                 :            :                     /* State is 6 most significant bits of aa_element_dword */
     536                 :          1 :                     aa_element_state = (aa_element_dword >> 20) & 0x3F;
     537                 :            : 
     538                 :            :                     /* vlan tagging requirement is the bit 1(left to right)
     539                 :            :                      * of the 6 bits state (1 based) */
     540                 :          1 :                     port->p_element.vlan_tagging =
     541                 :            :                         (aa_element_state >> 5) & 0x1;
     542                 :            : 
     543                 :            :                     /* Automatic provision mode is the bit 2/3(left to right)
     544                 :            :                      * of the 6 bits state (1 based) */
     545                 :          1 :                     port->p_element.auto_prov_mode =
     546                 :            :                         (aa_element_state >> 3) & 0x3;
     547                 :            : 
     548                 :            :                     /* mgmt_vlan is the 12 bits of aa_element_dword from
     549                 :            :                      * bit 12 */
     550                 :          1 :                     port->p_element.mgmt_vlan =
     551                 :          1 :                         (aa_element_dword >> 8) & 0xFFF;
     552         [ +  - ]:          1 :                     VLOG_INFO("Element type: %X, vlan tagging %X, "
     553                 :            :                               "auto prov mode %x, Mgmt vlan: %X",
     554                 :            :                               port->p_element.type,
     555                 :            :                               port->p_element.vlan_tagging,
     556                 :            :                               port->p_element.auto_prov_mode,
     557                 :            :                               port->p_element.mgmt_vlan);
     558                 :            : 
     559                 :          1 :                     PEEK_BYTES(&port->p_element.system_id.system_mac,
     560                 :            :                                sizeof port->p_element.system_id.system_mac);
     561         [ +  - ]:          1 :                     VLOG_INFO("System mac: "ETH_ADDR_FMT,
     562                 :            :                         ETH_ADDR_ARGS(port->p_element.system_id.system_mac));
     563                 :          1 :                     aa_system_id_word = PEEK_UINT16;
     564                 :          1 :                     port->p_element.system_id.conn_type =
     565                 :            :                         aa_system_id_word >> 13;
     566                 :          1 :                     port->p_element.system_id.rsvd = aa_system_id_word &
     567                 :            :                         0x03FF;
     568                 :          1 :                     PEEK_BYTES(&port->p_element.system_id.rsvd2,
     569                 :            :                                sizeof port->p_element.system_id.rsvd2);
     570                 :          1 :                     break;
     571                 :            : 
     572                 :            :                 case LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE:
     573                 :          1 :                     PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest);
     574                 :            : 
     575                 :            :                     /* Subtract off tlv type and length (2Bytes) + OUI (3B) +
     576                 :            :                      * Subtype (1B) + MSG DIGEST (32B).
     577                 :            :                      */
     578                 :          1 :                     num_mappings = tlv_size - 4 -
     579                 :            :                         LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH;
     580         [ -  + ]:          1 :                     if (num_mappings % 5 != 0) {
     581         [ #  # ]:          0 :                         VLOG_INFO("malformed vlan-isid mappings tlv received");
     582                 :          0 :                         goto malformed;
     583                 :            :                     }
     584                 :            : 
     585                 :          1 :                     num_mappings /= 5; /* Each mapping is 5 Bytes */
     586         [ +  + ]:          3 :                     for(; num_mappings > 0; num_mappings--) {
     587                 :            :                         uint8_t isid[3];
     588                 :            : 
     589                 :          2 :                         isid_vlan_map = xzalloc(sizeof *isid_vlan_map);
     590                 :          2 :                         aa_status_vlan_word = PEEK_UINT16;
     591                 :            : 
     592                 :            :                         /* Status is first 4 most-significant bits. */
     593                 :          2 :                         isid_vlan_map->isid_vlan_data.status =
     594                 :            :                             aa_status_vlan_word >> 12;
     595                 :            : 
     596                 :            :                         /* Vlan is last 12 bits */
     597                 :          2 :                         isid_vlan_map->isid_vlan_data.vlan =
     598                 :            :                             aa_status_vlan_word & 0x0FFF;
     599                 :          2 :                         PEEK_BYTES(isid, 3);
     600                 :          2 :                         isid_vlan_map->isid_vlan_data.isid =
     601                 :          2 :                             (isid[0] << 16) | (isid[1] << 8) | isid[2];
     602                 :          2 :                         ovs_list_push_back(&port->p_isid_vlan_maps,
     603                 :            :                                        &isid_vlan_map->m_entries);
     604                 :          2 :                         isid_vlan_map = NULL;
     605                 :            :                     }
     606                 :          1 :                     break;
     607                 :            : 
     608                 :            :                 default:
     609                 :          0 :                     hardware->h_rx_unrecognized_cnt++;
     610         [ #  # ]:          0 :                     VLOG_INFO("Unrecogised tlv subtype received");
     611                 :          2 :                     break;
     612                 :            :                 }
     613         [ #  # ]:          0 :             } else if (memcmp(dcbx, orgid, sizeof orgid) == 0) {
     614         [ #  # ]:          0 :                 VLOG_DBG("unsupported DCBX tlv received on %s "
     615                 :            :                          "- ignore", hardware->h_ifname);
     616                 :          0 :                 hardware->h_rx_unrecognized_cnt++;
     617                 :            :             } else {
     618         [ #  # ]:          0 :                 VLOG_INFO("unknown org tlv [%02x:%02x:%02x] received "
     619                 :            :                           "on %s", orgid[0], orgid[1], orgid[2],
     620                 :            :                           hardware->h_ifname);
     621                 :          0 :                 hardware->h_rx_unrecognized_cnt++;
     622                 :            :             }
     623                 :          2 :             break;
     624                 :            :         default:
     625         [ #  # ]:          0 :             VLOG_WARN("unknown tlv (%d) received on %s",
     626                 :            :                       tlv_type,
     627                 :            :                       hardware->h_ifname);
     628                 :          0 :             goto malformed;
     629                 :            :         }
     630         [ -  + ]:         10 :         if (pos > tlv + tlv_size) {
     631         [ #  # ]:          0 :             VLOG_WARN("BUG: already past TLV!");
     632                 :          0 :             goto malformed;
     633                 :            :         }
     634                 :         10 :         PEEK_DISCARD(tlv + tlv_size - pos);
     635                 :            :     }
     636                 :            : 
     637                 :            :     /* Some random check */
     638 [ +  - ][ +  - ]:          1 :     if (!chassis->c_id || !port->p_id || !ttl_received || !gotend) {
         [ +  - ][ -  + ]
     639         [ #  # ]:          0 :         VLOG_WARN("some mandatory tlv are missing for frame received "
     640                 :            :                   "on %s", hardware->h_ifname);
     641                 :          0 :         goto malformed;
     642                 :            :     }
     643                 :          1 :     *newchassis = chassis;
     644                 :          1 :     *newport = port;
     645                 :          1 :     return 1;
     646                 :            : 
     647                 :            : malformed:
     648                 :          0 :     lldpd_chassis_cleanup(chassis, true);
     649                 :          0 :     lldpd_port_cleanup(port, true);
     650                 :          0 :     free(port);
     651                 :          1 :     return -1;
     652                 :            : }

Generated by: LCOV version 1.12