LCOV - code coverage report
Current view: top level - libsystemd-network - lldp-neighbor.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 228 454 50.2 %
Date: 2019-08-23 13:36:53 Functions: 24 37 64.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 139 446 31.2 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include "alloc-util.h"
       4                 :            : #include "escape.h"
       5                 :            : #include "ether-addr-util.h"
       6                 :            : #include "hexdecoct.h"
       7                 :            : #include "in-addr-util.h"
       8                 :            : #include "lldp-internal.h"
       9                 :            : #include "lldp-neighbor.h"
      10                 :            : #include "memory-util.h"
      11                 :            : #include "missing.h"
      12                 :            : #include "unaligned.h"
      13                 :            : 
      14                 :        108 : static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) {
      15                 :        108 :         siphash24_compress(id->chassis_id, id->chassis_id_size, state);
      16                 :        108 :         siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state);
      17                 :        108 :         siphash24_compress(id->port_id, id->port_id_size, state);
      18                 :        108 :         siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state);
      19                 :        108 : }
      20                 :            : 
      21                 :         64 : int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y) {
      22                 :         64 :         return memcmp_nn(x->chassis_id, x->chassis_id_size, y->chassis_id, y->chassis_id_size)
      23         [ +  + ]:         64 :             ?: memcmp_nn(x->port_id, x->port_id_size, y->port_id, y->port_id_size);
      24                 :            : }
      25                 :            : 
      26                 :         32 : DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(lldp_neighbor_hash_ops, LLDPNeighborID, lldp_neighbor_id_hash_func, lldp_neighbor_id_compare_func,
      27                 :            :                                       sd_lldp_neighbor, lldp_neighbor_unlink);
      28                 :            : 
      29                 :        127 : int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
      30                 :        127 :         const sd_lldp_neighbor *x = a, *y = b;
      31                 :            : 
      32         [ +  + ]:        127 :         return CMP(x->until, y->until);
      33                 :            : }
      34                 :            : 
      35                 :         52 : _public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
      36         [ -  + ]:         52 :         if (!n)
      37                 :          0 :                 return NULL;
      38                 :            : 
      39   [ +  -  -  + ]:         52 :         assert(n->n_ref > 0 || n->lldp);
      40                 :         52 :         n->n_ref++;
      41                 :            : 
      42                 :         52 :         return n;
      43                 :            : }
      44                 :            : 
      45                 :         36 : static void lldp_neighbor_free(sd_lldp_neighbor *n) {
      46         [ -  + ]:         36 :         assert(n);
      47                 :            : 
      48                 :         36 :         free(n->id.port_id);
      49                 :         36 :         free(n->id.chassis_id);
      50                 :         36 :         free(n->port_description);
      51                 :         36 :         free(n->system_name);
      52                 :         36 :         free(n->system_description);
      53                 :         36 :         free(n->chassis_id_as_string);
      54                 :         36 :         free(n->port_id_as_string);
      55                 :         36 :         free(n);
      56                 :         36 : }
      57                 :            : 
      58                 :         88 : _public_ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) {
      59                 :            : 
      60                 :            :         /* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from
      61                 :            :          * the sd_lldp object. */
      62                 :            : 
      63         [ -  + ]:         88 :         if (!n)
      64                 :          0 :                 return NULL;
      65                 :            : 
      66         [ -  + ]:         88 :         assert(n->n_ref > 0);
      67                 :         88 :         n->n_ref--;
      68                 :            : 
      69   [ +  -  +  + ]:         88 :         if (n->n_ref <= 0 && !n->lldp)
      70                 :          4 :                 lldp_neighbor_free(n);
      71                 :            : 
      72                 :         88 :         return NULL;
      73                 :            : }
      74                 :            : 
      75                 :         32 : sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) {
      76                 :            : 
      77                 :            :         /* Removes the neighbor object from the LLDP object, and frees it if it also has no other reference. */
      78                 :            : 
      79         [ -  + ]:         32 :         if (!n)
      80                 :          0 :                 return NULL;
      81                 :            : 
      82         [ -  + ]:         32 :         if (!n->lldp)
      83                 :          0 :                 return NULL;
      84                 :            : 
      85                 :            :         /* Only remove the neighbor object from the hash table if it's in there, don't complain if it isn't. This is
      86                 :            :          * because we are used as destructor call for hashmap_clear() and thus sometimes are called to de-register
      87                 :            :          * ourselves from the hashtable and sometimes are called after we already are de-registered. */
      88                 :            : 
      89                 :         32 :         (void) hashmap_remove_value(n->lldp->neighbor_by_id, &n->id, n);
      90                 :            : 
      91         [ -  + ]:         32 :         assert_se(prioq_remove(n->lldp->neighbor_by_expiry, n, &n->prioq_idx) >= 0);
      92                 :            : 
      93                 :         32 :         n->lldp = NULL;
      94                 :            : 
      95         [ +  - ]:         32 :         if (n->n_ref <= 0)
      96                 :         32 :                 lldp_neighbor_free(n);
      97                 :            : 
      98                 :         32 :         return NULL;
      99                 :            : }
     100                 :            : 
     101                 :         36 : sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) {
     102                 :            :         sd_lldp_neighbor *n;
     103                 :            : 
     104                 :         36 :         n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size);
     105         [ -  + ]:         36 :         if (!n)
     106                 :          0 :                 return NULL;
     107                 :            : 
     108                 :         36 :         n->raw_size = raw_size;
     109                 :         36 :         n->n_ref = 1;
     110                 :            : 
     111                 :         36 :         return n;
     112                 :            : }
     113                 :            : 
     114                 :         12 : static int parse_string(char **s, const void *q, size_t n) {
     115                 :         12 :         const char *p = q;
     116                 :            :         char *k;
     117                 :            : 
     118         [ -  + ]:         12 :         assert(s);
     119   [ -  +  #  # ]:         12 :         assert(p || n == 0);
     120                 :            : 
     121         [ -  + ]:         12 :         if (*s) {
     122                 :          0 :                 log_lldp("Found duplicate string, ignoring field.");
     123                 :          0 :                 return 0;
     124                 :            :         }
     125                 :            : 
     126                 :            :         /* Strip trailing NULs, just to be nice */
     127   [ +  -  +  + ]:         16 :         while (n > 0 && p[n-1] == 0)
     128                 :          4 :                 n--;
     129                 :            : 
     130         [ -  + ]:         12 :         if (n <= 0) /* Ignore empty strings */
     131                 :          0 :                 return 0;
     132                 :            : 
     133                 :            :         /* Look for inner NULs */
     134         [ -  + ]:         12 :         if (memchr(p, 0, n)) {
     135                 :          0 :                 log_lldp("Found inner NUL in string, ignoring field.");
     136                 :          0 :                 return 0;
     137                 :            :         }
     138                 :            : 
     139                 :            :         /* Let's escape weird chars, for security reasons */
     140                 :         12 :         k = cescape_length(p, n);
     141         [ -  + ]:         12 :         if (!k)
     142                 :          0 :                 return -ENOMEM;
     143                 :            : 
     144                 :         12 :         free(*s);
     145                 :         12 :         *s = k;
     146                 :            : 
     147                 :         12 :         return 1;
     148                 :            : }
     149                 :            : 
     150                 :         36 : int lldp_neighbor_parse(sd_lldp_neighbor *n) {
     151                 :            :         struct ether_header h;
     152                 :            :         const uint8_t *p;
     153                 :            :         size_t left;
     154                 :            :         int r;
     155                 :            : 
     156         [ -  + ]:         36 :         assert(n);
     157                 :            : 
     158         [ -  + ]:         36 :         if (n->raw_size < sizeof(struct ether_header)) {
     159                 :          0 :                 log_lldp("Received truncated packet, ignoring.");
     160                 :          0 :                 return -EBADMSG;
     161                 :            :         }
     162                 :            : 
     163                 :         36 :         memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h));
     164                 :            : 
     165         [ -  + ]:         36 :         if (h.ether_type != htobe16(ETHERTYPE_LLDP)) {
     166                 :          0 :                 log_lldp("Received packet with wrong type, ignoring.");
     167                 :          0 :                 return -EBADMSG;
     168                 :            :         }
     169                 :            : 
     170         [ +  - ]:         36 :         if (h.ether_dhost[0] != 0x01 ||
     171         [ +  - ]:         36 :             h.ether_dhost[1] != 0x80 ||
     172         [ +  - ]:         36 :             h.ether_dhost[2] != 0xc2 ||
     173         [ +  - ]:         36 :             h.ether_dhost[3] != 0x00 ||
     174         [ +  - ]:         36 :             h.ether_dhost[4] != 0x00 ||
     175   [ +  -  -  + ]:         36 :             !IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e)) {
     176                 :          0 :                 log_lldp("Received packet with wrong destination address, ignoring.");
     177                 :          0 :                 return -EBADMSG;
     178                 :            :         }
     179                 :            : 
     180                 :         36 :         memcpy(&n->source_address, h.ether_shost, sizeof(struct ether_addr));
     181                 :         36 :         memcpy(&n->destination_address, h.ether_dhost, sizeof(struct ether_addr));
     182                 :            : 
     183                 :         36 :         p = (const uint8_t*) LLDP_NEIGHBOR_RAW(n) + sizeof(struct ether_header);
     184                 :         36 :         left = n->raw_size - sizeof(struct ether_header);
     185                 :            : 
     186                 :        140 :         for (;;) {
     187                 :            :                 uint8_t type;
     188                 :            :                 uint16_t length;
     189                 :            : 
     190         [ -  + ]:        176 :                 if (left < 2) {
     191                 :          0 :                         log_lldp("TLV lacks header, ignoring.");
     192                 :          0 :                         return -EBADMSG;
     193                 :            :                 }
     194                 :            : 
     195                 :        176 :                 type = p[0] >> 1;
     196                 :        176 :                 length = p[1] + (((uint16_t) (p[0] & 1)) << 8);
     197                 :        176 :                 p += 2, left -= 2;
     198                 :            : 
     199         [ -  + ]:        176 :                 if (left < length) {
     200                 :          0 :                         log_lldp("TLV truncated, ignoring datagram.");
     201                 :          0 :                         return -EBADMSG;
     202                 :            :                 }
     203                 :            : 
     204   [ +  +  +  +  :        176 :                 switch (type) {
          +  +  +  -  +  
                      - ]
     205                 :            : 
     206                 :         36 :                 case SD_LLDP_TYPE_END:
     207         [ -  + ]:         36 :                         if (length != 0) {
     208                 :          0 :                                 log_lldp("End marker TLV not zero-sized, ignoring datagram.");
     209                 :          0 :                                 return -EBADMSG;
     210                 :            :                         }
     211                 :            : 
     212                 :            :                         /* Note that after processing the SD_LLDP_TYPE_END left could still be > 0
     213                 :            :                          * as the message may contain padding (see IEEE 802.1AB-2016, sec. 8.5.12) */
     214                 :            : 
     215                 :         36 :                         goto end_marker;
     216                 :            : 
     217                 :         36 :                 case SD_LLDP_TYPE_CHASSIS_ID:
     218   [ +  -  -  + ]:         36 :                         if (length < 2 || length > 256) { /* includes the chassis subtype, hence one extra byte */
     219                 :          0 :                                 log_lldp("Chassis ID field size out of range, ignoring datagram.");
     220                 :          0 :                                 return -EBADMSG;
     221                 :            :                         }
     222         [ -  + ]:         36 :                         if (n->id.chassis_id) {
     223                 :          0 :                                 log_lldp("Duplicate chassis ID field, ignoring datagram.");
     224                 :          0 :                                 return -EBADMSG;
     225                 :            :                         }
     226                 :            : 
     227                 :         36 :                         n->id.chassis_id = memdup(p, length);
     228         [ -  + ]:         36 :                         if (!n->id.chassis_id)
     229                 :          0 :                                 return -ENOMEM;
     230                 :            : 
     231                 :         36 :                         n->id.chassis_id_size = length;
     232                 :         36 :                         break;
     233                 :            : 
     234                 :         36 :                 case SD_LLDP_TYPE_PORT_ID:
     235   [ +  -  -  + ]:         36 :                         if (length < 2 || length > 256) { /* includes the port subtype, hence one extra byte */
     236                 :          0 :                                 log_lldp("Port ID field size out of range, ignoring datagram.");
     237                 :          0 :                                 return -EBADMSG;
     238                 :            :                         }
     239         [ -  + ]:         36 :                         if (n->id.port_id) {
     240                 :          0 :                                 log_lldp("Duplicate port ID field, ignoring datagram.");
     241                 :          0 :                                 return -EBADMSG;
     242                 :            :                         }
     243                 :            : 
     244                 :         36 :                         n->id.port_id = memdup(p, length);
     245         [ -  + ]:         36 :                         if (!n->id.port_id)
     246                 :          0 :                                 return -ENOMEM;
     247                 :            : 
     248                 :         36 :                         n->id.port_id_size = length;
     249                 :         36 :                         break;
     250                 :            : 
     251                 :         32 :                 case SD_LLDP_TYPE_TTL:
     252         [ -  + ]:         32 :                         if (length != 2) {
     253                 :          0 :                                 log_lldp("TTL field has wrong size, ignoring datagram.");
     254                 :          0 :                                 return -EBADMSG;
     255                 :            :                         }
     256                 :            : 
     257         [ -  + ]:         32 :                         if (n->has_ttl) {
     258                 :          0 :                                 log_lldp("Duplicate TTL field, ignoring datagram.");
     259                 :          0 :                                 return -EBADMSG;
     260                 :            :                         }
     261                 :            : 
     262                 :         32 :                         n->ttl = unaligned_read_be16(p);
     263                 :         32 :                         n->has_ttl = true;
     264                 :         32 :                         break;
     265                 :            : 
     266                 :          4 :                 case SD_LLDP_TYPE_PORT_DESCRIPTION:
     267                 :          4 :                         r = parse_string(&n->port_description, p, length);
     268         [ -  + ]:          4 :                         if (r < 0)
     269                 :          0 :                                 return r;
     270                 :          4 :                         break;
     271                 :            : 
     272                 :          4 :                 case SD_LLDP_TYPE_SYSTEM_NAME:
     273                 :          4 :                         r = parse_string(&n->system_name, p, length);
     274         [ -  + ]:          4 :                         if (r < 0)
     275                 :          0 :                                 return r;
     276                 :          4 :                         break;
     277                 :            : 
     278                 :          4 :                 case SD_LLDP_TYPE_SYSTEM_DESCRIPTION:
     279                 :          4 :                         r = parse_string(&n->system_description, p, length);
     280         [ -  + ]:          4 :                         if (r < 0)
     281                 :          0 :                                 return r;
     282                 :          4 :                         break;
     283                 :            : 
     284                 :          0 :                 case SD_LLDP_TYPE_SYSTEM_CAPABILITIES:
     285         [ #  # ]:          0 :                         if (length != 4)
     286                 :          0 :                                 log_lldp("System capabilities field has wrong size, ignoring.");
     287                 :            :                         else {
     288                 :          0 :                                 n->system_capabilities = unaligned_read_be16(p);
     289                 :          0 :                                 n->enabled_capabilities = unaligned_read_be16(p + 2);
     290                 :          0 :                                 n->has_capabilities = true;
     291                 :            :                         }
     292                 :            : 
     293                 :          0 :                         break;
     294                 :            : 
     295                 :         24 :                 case SD_LLDP_TYPE_PRIVATE:
     296         [ -  + ]:         24 :                         if (length < 4)
     297                 :          0 :                                 log_lldp("Found private TLV that is too short, ignoring.");
     298                 :            : 
     299                 :         24 :                         break;
     300                 :            :                 }
     301                 :            : 
     302                 :        140 :                 p += length, left -= length;
     303                 :            :         }
     304                 :            : 
     305                 :         36 : end_marker:
     306   [ +  -  +  -  :         36 :         if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl) {
                   +  + ]
     307                 :          4 :                 log_lldp("One or more mandatory TLV missing in datagram. Ignoring.");
     308                 :          4 :                 return -EBADMSG;
     309                 :            : 
     310                 :            :         }
     311                 :            : 
     312                 :         32 :         n->rindex = sizeof(struct ether_header);
     313                 :            : 
     314                 :         32 :         return 0;
     315                 :            : }
     316                 :            : 
     317                 :         32 : void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) {
     318         [ -  + ]:         32 :         assert(n);
     319                 :            : 
     320         [ +  - ]:         32 :         if (n->ttl > 0) {
     321                 :            :                 usec_t base;
     322                 :            : 
     323                 :            :                 /* Use the packet's timestamp if there is one known */
     324                 :         32 :                 base = triple_timestamp_by_clock(&n->timestamp, clock_boottime_or_monotonic());
     325   [ +  -  -  + ]:         32 :                 if (base <= 0 || base == USEC_INFINITY)
     326                 :          0 :                         base = now(clock_boottime_or_monotonic()); /* Otherwise, take the current time */
     327                 :            : 
     328                 :         32 :                 n->until = usec_add(base, n->ttl * USEC_PER_SEC);
     329                 :            :         } else
     330                 :          0 :                 n->until = 0;
     331                 :            : 
     332         [ +  - ]:         32 :         if (n->lldp)
     333                 :         32 :                 prioq_reshuffle(n->lldp->neighbor_by_expiry, n, &n->prioq_idx);
     334                 :         32 : }
     335                 :            : 
     336                 :          0 : bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) {
     337         [ #  # ]:          0 :         if (a == b)
     338                 :          0 :                 return true;
     339                 :            : 
     340   [ #  #  #  # ]:          0 :         if (!a || !b)
     341                 :          0 :                 return false;
     342                 :            : 
     343         [ #  # ]:          0 :         if (a->raw_size != b->raw_size)
     344                 :          0 :                 return false;
     345                 :            : 
     346                 :          0 :         return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0;
     347                 :            : }
     348                 :            : 
     349                 :          0 : _public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) {
     350   [ #  #  #  # ]:          0 :         assert_return(n, -EINVAL);
     351   [ #  #  #  # ]:          0 :         assert_return(address, -EINVAL);
     352                 :            : 
     353                 :          0 :         *address = n->source_address;
     354                 :          0 :         return 0;
     355                 :            : }
     356                 :            : 
     357                 :          0 : _public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) {
     358   [ #  #  #  # ]:          0 :         assert_return(n, -EINVAL);
     359   [ #  #  #  # ]:          0 :         assert_return(address, -EINVAL);
     360                 :            : 
     361                 :          0 :         *address = n->destination_address;
     362                 :          0 :         return 0;
     363                 :            : }
     364                 :            : 
     365                 :          0 : _public_ int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
     366   [ #  #  #  # ]:          0 :         assert_return(n, -EINVAL);
     367   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
     368   [ #  #  #  # ]:          0 :         assert_return(size, -EINVAL);
     369                 :            : 
     370                 :          0 :         *ret = LLDP_NEIGHBOR_RAW(n);
     371                 :          0 :         *size = n->raw_size;
     372                 :            : 
     373                 :          0 :         return 0;
     374                 :            : }
     375                 :            : 
     376                 :         28 : _public_ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
     377   [ -  +  -  + ]:         28 :         assert_return(n, -EINVAL);
     378   [ -  +  -  + ]:         28 :         assert_return(type, -EINVAL);
     379   [ -  +  -  + ]:         28 :         assert_return(ret, -EINVAL);
     380   [ -  +  -  + ]:         28 :         assert_return(size, -EINVAL);
     381                 :            : 
     382         [ -  + ]:         28 :         assert(n->id.chassis_id_size > 0);
     383                 :            : 
     384                 :         28 :         *type = *(uint8_t*) n->id.chassis_id;
     385                 :         28 :         *ret = (uint8_t*) n->id.chassis_id + 1;
     386                 :         28 :         *size = n->id.chassis_id_size - 1;
     387                 :            : 
     388                 :         28 :         return 0;
     389                 :            : }
     390                 :            : 
     391                 :          0 : static int format_mac_address(const void *data, size_t sz, char **ret) {
     392                 :            :         struct ether_addr a;
     393                 :            :         char *k;
     394                 :            : 
     395   [ #  #  #  # ]:          0 :         assert(data || sz <= 0);
     396                 :            : 
     397         [ #  # ]:          0 :         if (sz != 7)
     398                 :          0 :                 return 0;
     399                 :            : 
     400                 :          0 :         memcpy(&a, (uint8_t*) data + 1, sizeof(a));
     401                 :            : 
     402                 :          0 :         k = new(char, ETHER_ADDR_TO_STRING_MAX);
     403         [ #  # ]:          0 :         if (!k)
     404                 :          0 :                 return -ENOMEM;
     405                 :            : 
     406                 :          0 :         *ret = ether_addr_to_string(&a, k);
     407                 :          0 :         return 1;
     408                 :            : }
     409                 :            : 
     410                 :          0 : static int format_network_address(const void *data, size_t sz, char **ret) {
     411                 :            :         union in_addr_union a;
     412                 :            :         int family, r;
     413                 :            : 
     414   [ #  #  #  # ]:          0 :         if (sz == 6 && ((uint8_t*) data)[1] == 1) {
     415                 :          0 :                 memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in));
     416                 :          0 :                 family = AF_INET;
     417   [ #  #  #  # ]:          0 :         } else if (sz == 18 && ((uint8_t*) data)[1] == 2) {
     418                 :          0 :                 memcpy(&a.in6, (uint8_t*) data + 2, sizeof(a.in6));
     419                 :          0 :                 family = AF_INET6;
     420                 :            :         } else
     421                 :          0 :                 return 0;
     422                 :            : 
     423                 :          0 :         r = in_addr_to_string(family, &a, ret);
     424         [ #  # ]:          0 :         if (r < 0)
     425                 :          0 :                 return r;
     426                 :          0 :         return 1;
     427                 :            : }
     428                 :            : 
     429                 :          0 : _public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) {
     430                 :            :         char *k;
     431                 :            :         int r;
     432                 :            : 
     433   [ #  #  #  # ]:          0 :         assert_return(n, -EINVAL);
     434   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
     435                 :            : 
     436         [ #  # ]:          0 :         if (n->chassis_id_as_string) {
     437                 :          0 :                 *ret = n->chassis_id_as_string;
     438                 :          0 :                 return 0;
     439                 :            :         }
     440                 :            : 
     441         [ #  # ]:          0 :         assert(n->id.chassis_id_size > 0);
     442                 :            : 
     443   [ #  #  #  # ]:          0 :         switch (*(uint8_t*) n->id.chassis_id) {
     444                 :            : 
     445                 :          0 :         case SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT:
     446                 :            :         case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS:
     447                 :            :         case SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT:
     448                 :            :         case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME:
     449                 :            :         case SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED:
     450                 :          0 :                 k = cescape_length((char*) n->id.chassis_id + 1, n->id.chassis_id_size - 1);
     451         [ #  # ]:          0 :                 if (!k)
     452                 :          0 :                         return -ENOMEM;
     453                 :            : 
     454                 :          0 :                 goto done;
     455                 :            : 
     456                 :          0 :         case SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
     457                 :          0 :                 r = format_mac_address(n->id.chassis_id, n->id.chassis_id_size, &k);
     458         [ #  # ]:          0 :                 if (r < 0)
     459                 :          0 :                         return r;
     460         [ #  # ]:          0 :                 if (r > 0)
     461                 :          0 :                         goto done;
     462                 :            : 
     463                 :          0 :                 break;
     464                 :            : 
     465                 :          0 :         case SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS:
     466                 :          0 :                 r = format_network_address(n->id.chassis_id, n->id.chassis_id_size, &k);
     467         [ #  # ]:          0 :                 if (r < 0)
     468                 :          0 :                         return r;
     469         [ #  # ]:          0 :                 if (r > 0)
     470                 :          0 :                         goto done;
     471                 :            : 
     472                 :          0 :                 break;
     473                 :            :         }
     474                 :            : 
     475                 :            :         /* Generic fallback */
     476                 :          0 :         k = hexmem(n->id.chassis_id, n->id.chassis_id_size);
     477         [ #  # ]:          0 :         if (!k)
     478                 :          0 :                 return -ENOMEM;
     479                 :            : 
     480                 :          0 : done:
     481                 :          0 :         *ret = n->chassis_id_as_string = k;
     482                 :          0 :         return 0;
     483                 :            : }
     484                 :            : 
     485                 :         28 : _public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
     486   [ -  +  -  + ]:         28 :         assert_return(n, -EINVAL);
     487   [ -  +  -  + ]:         28 :         assert_return(type, -EINVAL);
     488   [ -  +  -  + ]:         28 :         assert_return(ret, -EINVAL);
     489   [ -  +  -  + ]:         28 :         assert_return(size, -EINVAL);
     490                 :            : 
     491         [ -  + ]:         28 :         assert(n->id.port_id_size > 0);
     492                 :            : 
     493                 :         28 :         *type = *(uint8_t*) n->id.port_id;
     494                 :         28 :         *ret = (uint8_t*) n->id.port_id + 1;
     495                 :         28 :         *size = n->id.port_id_size - 1;
     496                 :            : 
     497                 :         28 :         return 0;
     498                 :            : }
     499                 :            : 
     500                 :          0 : _public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) {
     501                 :            :         char *k;
     502                 :            :         int r;
     503                 :            : 
     504   [ #  #  #  # ]:          0 :         assert_return(n, -EINVAL);
     505   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
     506                 :            : 
     507         [ #  # ]:          0 :         if (n->port_id_as_string) {
     508                 :          0 :                 *ret = n->port_id_as_string;
     509                 :          0 :                 return 0;
     510                 :            :         }
     511                 :            : 
     512         [ #  # ]:          0 :         assert(n->id.port_id_size > 0);
     513                 :            : 
     514   [ #  #  #  # ]:          0 :         switch (*(uint8_t*) n->id.port_id) {
     515                 :            : 
     516                 :          0 :         case SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
     517                 :            :         case SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT:
     518                 :            :         case SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME:
     519                 :            :         case SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
     520                 :          0 :                 k = cescape_length((char*) n->id.port_id + 1, n->id.port_id_size - 1);
     521         [ #  # ]:          0 :                 if (!k)
     522                 :          0 :                         return -ENOMEM;
     523                 :            : 
     524                 :          0 :                 goto done;
     525                 :            : 
     526                 :          0 :         case SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS:
     527                 :          0 :                 r = format_mac_address(n->id.port_id, n->id.port_id_size, &k);
     528         [ #  # ]:          0 :                 if (r < 0)
     529                 :          0 :                         return r;
     530         [ #  # ]:          0 :                 if (r > 0)
     531                 :          0 :                         goto done;
     532                 :            : 
     533                 :          0 :                 break;
     534                 :            : 
     535                 :          0 :         case SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS:
     536                 :          0 :                 r = format_network_address(n->id.port_id, n->id.port_id_size, &k);
     537         [ #  # ]:          0 :                 if (r < 0)
     538                 :          0 :                         return r;
     539         [ #  # ]:          0 :                 if (r > 0)
     540                 :          0 :                         goto done;
     541                 :            : 
     542                 :          0 :                 break;
     543                 :            :         }
     544                 :            : 
     545                 :            :         /* Generic fallback */
     546                 :          0 :         k = hexmem(n->id.port_id, n->id.port_id_size);
     547         [ #  # ]:          0 :         if (!k)
     548                 :          0 :                 return -ENOMEM;
     549                 :            : 
     550                 :          0 : done:
     551                 :          0 :         *ret = n->port_id_as_string = k;
     552                 :          0 :         return 0;
     553                 :            : }
     554                 :            : 
     555                 :         28 : _public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) {
     556   [ -  +  -  + ]:         28 :         assert_return(n, -EINVAL);
     557   [ -  +  -  + ]:         28 :         assert_return(ret_sec, -EINVAL);
     558                 :            : 
     559                 :         28 :         *ret_sec = n->ttl;
     560                 :         28 :         return 0;
     561                 :            : }
     562                 :            : 
     563                 :          4 : _public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) {
     564   [ -  +  -  + ]:          4 :         assert_return(n, -EINVAL);
     565   [ -  +  -  + ]:          4 :         assert_return(ret, -EINVAL);
     566                 :            : 
     567         [ -  + ]:          4 :         if (!n->system_name)
     568                 :          0 :                 return -ENODATA;
     569                 :            : 
     570                 :          4 :         *ret = n->system_name;
     571                 :          4 :         return 0;
     572                 :            : }
     573                 :            : 
     574                 :          4 : _public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) {
     575   [ -  +  -  + ]:          4 :         assert_return(n, -EINVAL);
     576   [ -  +  -  + ]:          4 :         assert_return(ret, -EINVAL);
     577                 :            : 
     578         [ -  + ]:          4 :         if (!n->system_description)
     579                 :          0 :                 return -ENODATA;
     580                 :            : 
     581                 :          4 :         *ret = n->system_description;
     582                 :          4 :         return 0;
     583                 :            : }
     584                 :            : 
     585                 :          4 : _public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) {
     586   [ -  +  -  + ]:          4 :         assert_return(n, -EINVAL);
     587   [ -  +  -  + ]:          4 :         assert_return(ret, -EINVAL);
     588                 :            : 
     589         [ -  + ]:          4 :         if (!n->port_description)
     590                 :          0 :                 return -ENODATA;
     591                 :            : 
     592                 :          4 :         *ret = n->port_description;
     593                 :          4 :         return 0;
     594                 :            : }
     595                 :            : 
     596                 :          0 : _public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
     597   [ #  #  #  # ]:          0 :         assert_return(n, -EINVAL);
     598   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
     599                 :            : 
     600         [ #  # ]:          0 :         if (!n->has_capabilities)
     601                 :          0 :                 return -ENODATA;
     602                 :            : 
     603                 :          0 :         *ret = n->system_capabilities;
     604                 :          0 :         return 0;
     605                 :            : }
     606                 :            : 
     607                 :          0 : _public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
     608   [ #  #  #  # ]:          0 :         assert_return(n, -EINVAL);
     609   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
     610                 :            : 
     611         [ #  # ]:          0 :         if (!n->has_capabilities)
     612                 :          0 :                 return -ENODATA;
     613                 :            : 
     614                 :          0 :         *ret = n->enabled_capabilities;
     615                 :          0 :         return 0;
     616                 :            : }
     617                 :            : 
     618                 :          0 : _public_ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
     619                 :          0 :         _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
     620                 :            :         int r;
     621                 :            : 
     622   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
     623   [ #  #  #  #  :          0 :         assert_return(raw || raw_size <= 0, -EINVAL);
                   #  # ]
     624                 :            : 
     625                 :          0 :         n = lldp_neighbor_new(raw_size);
     626         [ #  # ]:          0 :         if (!n)
     627                 :          0 :                 return -ENOMEM;
     628                 :            : 
     629                 :          0 :         memcpy(LLDP_NEIGHBOR_RAW(n), raw, raw_size);
     630                 :          0 :         r = lldp_neighbor_parse(n);
     631         [ #  # ]:          0 :         if (r < 0)
     632                 :          0 :                 return r;
     633                 :            : 
     634                 :          0 :         *ret = TAKE_PTR(n);
     635                 :            : 
     636                 :          0 :         return r;
     637                 :            : }
     638                 :            : 
     639                 :          4 : _public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
     640   [ -  +  -  + ]:          4 :         assert_return(n, -EINVAL);
     641                 :            : 
     642         [ -  + ]:          4 :         assert(n->raw_size >= sizeof(struct ether_header));
     643                 :          4 :         n->rindex = sizeof(struct ether_header);
     644                 :            : 
     645                 :          4 :         return n->rindex < n->raw_size;
     646                 :            : }
     647                 :            : 
     648                 :         40 : _public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
     649                 :            :         size_t length;
     650                 :            : 
     651   [ -  +  -  + ]:         40 :         assert_return(n, -EINVAL);
     652                 :            : 
     653         [ -  + ]:         40 :         if (n->rindex == n->raw_size) /* EOF */
     654                 :          0 :                 return -ESPIPE;
     655                 :            : 
     656         [ -  + ]:         40 :         if (n->rindex + 2 > n->raw_size) /* Truncated message */
     657                 :          0 :                 return -EBADMSG;
     658                 :            : 
     659                 :         40 :         length = LLDP_NEIGHBOR_TLV_LENGTH(n);
     660         [ -  + ]:         40 :         if (n->rindex + 2 + length > n->raw_size)
     661                 :          0 :                 return -EBADMSG;
     662                 :            : 
     663                 :         40 :         n->rindex += 2 + length;
     664                 :         40 :         return n->rindex < n->raw_size;
     665                 :            : }
     666                 :            : 
     667                 :         40 : _public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
     668   [ -  +  -  + ]:         40 :         assert_return(n, -EINVAL);
     669   [ -  +  -  + ]:         40 :         assert_return(type, -EINVAL);
     670                 :            : 
     671         [ -  + ]:         40 :         if (n->rindex == n->raw_size) /* EOF */
     672                 :          0 :                 return -ESPIPE;
     673                 :            : 
     674         [ -  + ]:         40 :         if (n->rindex + 2 > n->raw_size)
     675                 :          0 :                 return -EBADMSG;
     676                 :            : 
     677                 :         40 :         *type = LLDP_NEIGHBOR_TLV_TYPE(n);
     678                 :         40 :         return 0;
     679                 :            : }
     680                 :            : 
     681                 :         40 : _public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
     682                 :            :         uint8_t k;
     683                 :            :         int r;
     684                 :            : 
     685   [ -  +  -  + ]:         40 :         assert_return(n, -EINVAL);
     686                 :            : 
     687                 :         40 :         r = sd_lldp_neighbor_tlv_get_type(n, &k);
     688         [ -  + ]:         40 :         if (r < 0)
     689                 :          0 :                 return r;
     690                 :            : 
     691                 :         40 :         return type == k;
     692                 :            : }
     693                 :            : 
     694                 :         24 : _public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype) {
     695                 :            :         const uint8_t *d;
     696                 :            :         size_t length;
     697                 :            :         int r;
     698                 :            : 
     699   [ -  +  -  + ]:         24 :         assert_return(n, -EINVAL);
     700   [ -  +  -  + ]:         24 :         assert_return(oui, -EINVAL);
     701   [ -  +  -  + ]:         24 :         assert_return(subtype, -EINVAL);
     702                 :            : 
     703                 :         24 :         r = sd_lldp_neighbor_tlv_is_type(n, SD_LLDP_TYPE_PRIVATE);
     704         [ -  + ]:         24 :         if (r < 0)
     705                 :          0 :                 return r;
     706         [ -  + ]:         24 :         if (r == 0)
     707                 :          0 :                 return -ENXIO;
     708                 :            : 
     709                 :         24 :         length = LLDP_NEIGHBOR_TLV_LENGTH(n);
     710         [ -  + ]:         24 :         if (length < 4)
     711                 :          0 :                 return -EBADMSG;
     712                 :            : 
     713         [ -  + ]:         24 :         if (n->rindex + 2 + length > n->raw_size)
     714                 :          0 :                 return -EBADMSG;
     715                 :            : 
     716                 :         24 :         d = LLDP_NEIGHBOR_TLV_DATA(n);
     717                 :         24 :         memcpy(oui, d, 3);
     718                 :         24 :         *subtype = d[3];
     719                 :            : 
     720                 :         24 :         return 0;
     721                 :            : }
     722                 :            : 
     723                 :         24 : _public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype) {
     724                 :            :         uint8_t k[3], st;
     725                 :            :         int r;
     726                 :            : 
     727                 :         24 :         r = sd_lldp_neighbor_tlv_get_oui(n, k, &st);
     728         [ -  + ]:         24 :         if (r == -ENXIO)
     729                 :          0 :                 return 0;
     730         [ -  + ]:         24 :         if (r < 0)
     731                 :          0 :                 return r;
     732                 :            : 
     733   [ +  -  +  - ]:         24 :         return memcmp(k, oui, 3) == 0 && st == subtype;
     734                 :            : }
     735                 :            : 
     736                 :          0 : _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
     737                 :            :         size_t length;
     738                 :            : 
     739   [ #  #  #  # ]:          0 :         assert_return(n, -EINVAL);
     740   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
     741   [ #  #  #  # ]:          0 :         assert_return(size, -EINVAL);
     742                 :            : 
     743                 :            :         /* Note that this returns the full TLV, including the TLV header */
     744                 :            : 
     745         [ #  # ]:          0 :         if (n->rindex + 2 > n->raw_size)
     746                 :          0 :                 return -EBADMSG;
     747                 :            : 
     748                 :          0 :         length = LLDP_NEIGHBOR_TLV_LENGTH(n);
     749         [ #  # ]:          0 :         if (n->rindex + 2 + length > n->raw_size)
     750                 :          0 :                 return -EBADMSG;
     751                 :            : 
     752                 :          0 :         *ret = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex;
     753                 :          0 :         *size = length + 2;
     754                 :            : 
     755                 :          0 :         return 0;
     756                 :            : }
     757                 :            : 
     758                 :          0 : _public_ int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) {
     759   [ #  #  #  # ]:          0 :         assert_return(n, -EINVAL);
     760   [ #  #  #  #  :          0 :         assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
                   #  # ]
     761   [ #  #  #  # ]:          0 :         assert_return(clock_supported(clock), -EOPNOTSUPP);
     762   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
     763                 :            : 
     764         [ #  # ]:          0 :         if (!triple_timestamp_is_set(&n->timestamp))
     765                 :          0 :                 return -ENODATA;
     766                 :            : 
     767                 :          0 :         *ret = triple_timestamp_by_clock(&n->timestamp, clock);
     768                 :          0 :         return 0;
     769                 :            : }

Generated by: LCOV version 1.14