LCOV - code coverage report
Current view: top level - libsystemd-network - sd-lldp.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 179 270 66.3 %
Date: 2019-08-23 13:36:53 Functions: 22 28 78.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 104 242 43.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <arpa/inet.h>
       4                 :            : #include <linux/sockios.h>
       5                 :            : #include <sys/ioctl.h>
       6                 :            : 
       7                 :            : #include "sd-lldp.h"
       8                 :            : 
       9                 :            : #include "alloc-util.h"
      10                 :            : #include "ether-addr-util.h"
      11                 :            : #include "event-util.h"
      12                 :            : #include "fd-util.h"
      13                 :            : #include "lldp-internal.h"
      14                 :            : #include "lldp-neighbor.h"
      15                 :            : #include "lldp-network.h"
      16                 :            : #include "memory-util.h"
      17                 :            : #include "socket-util.h"
      18                 :            : #include "sort-util.h"
      19                 :            : #include "string-table.h"
      20                 :            : 
      21                 :            : #define LLDP_DEFAULT_NEIGHBORS_MAX 128U
      22                 :            : 
      23                 :            : static const char * const lldp_event_table[_SD_LLDP_EVENT_MAX] = {
      24                 :            :         [SD_LLDP_EVENT_ADDED]   = "added",
      25                 :            :         [SD_LLDP_EVENT_REMOVED] = "removed",
      26                 :            :         [SD_LLDP_EVENT_UPDATED]   = "updated",
      27                 :            :         [SD_LLDP_EVENT_REFRESHED] = "refreshed",
      28                 :            : };
      29                 :            : 
      30   [ +  +  +  + ]:         80 : DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event);
      31                 :            : 
      32                 :         32 : static void lldp_flush_neighbors(sd_lldp *lldp) {
      33         [ -  + ]:         32 :         assert(lldp);
      34                 :            : 
      35                 :         32 :         hashmap_clear(lldp->neighbor_by_id);
      36                 :         32 : }
      37                 :            : 
      38                 :         32 : static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) {
      39         [ -  + ]:         32 :         assert(lldp);
      40   [ +  -  -  + ]:         32 :         assert(event >= 0 && event < _SD_LLDP_EVENT_MAX);
      41                 :            : 
      42         [ -  + ]:         32 :         if (!lldp->callback) {
      43                 :          0 :                 log_lldp("Received '%s' event.", lldp_event_to_string(event));
      44                 :          0 :                 return;
      45                 :            :         }
      46                 :            : 
      47                 :         32 :         log_lldp("Invoking callback for '%s' event.", lldp_event_to_string(event));
      48                 :         32 :         lldp->callback(lldp, event, n, lldp->userdata);
      49                 :            : }
      50                 :            : 
      51                 :         32 : static int lldp_make_space(sd_lldp *lldp, size_t extra) {
      52                 :         32 :         usec_t t = USEC_INFINITY;
      53                 :         32 :         bool changed = false;
      54                 :            : 
      55         [ -  + ]:         32 :         assert(lldp);
      56                 :            : 
      57                 :            :         /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries
      58                 :            :          * are free. */
      59                 :            : 
      60                 :          0 :         for (;;) {
      61         [ -  + ]:         32 :                 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
      62                 :            : 
      63                 :         32 :                 n = prioq_peek(lldp->neighbor_by_expiry);
      64         [ +  + ]:         32 :                 if (!n)
      65                 :         12 :                         break;
      66                 :            : 
      67                 :         20 :                 sd_lldp_neighbor_ref(n);
      68                 :            : 
      69   [ +  -  -  + ]:         20 :                 if (hashmap_size(lldp->neighbor_by_id) > LESS_BY(lldp->neighbors_max, extra))
      70                 :          0 :                         goto remove_one;
      71                 :            : 
      72         [ +  - ]:         20 :                 if (t == USEC_INFINITY)
      73                 :         20 :                         t = now(clock_boottime_or_monotonic());
      74                 :            : 
      75         [ +  - ]:         20 :                 if (n->until > t)
      76                 :         20 :                         break;
      77                 :            : 
      78                 :          0 :         remove_one:
      79                 :          0 :                 lldp_neighbor_unlink(n);
      80                 :          0 :                 lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n);
      81                 :          0 :                 changed = true;
      82                 :            :         }
      83                 :            : 
      84                 :         32 :         return changed;
      85                 :            : }
      86                 :            : 
      87                 :         32 : static bool lldp_keep_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) {
      88         [ -  + ]:         32 :         assert(lldp);
      89         [ -  + ]:         32 :         assert(n);
      90                 :            : 
      91                 :            :         /* Don't keep data with a zero TTL */
      92         [ -  + ]:         32 :         if (n->ttl <= 0)
      93                 :          0 :                 return false;
      94                 :            : 
      95                 :            :         /* Filter out data from the filter address */
      96   [ -  +  #  # ]:         32 :         if (!ether_addr_is_null(&lldp->filter_address) &&
      97                 :          0 :             ether_addr_equal(&lldp->filter_address, &n->source_address))
      98                 :          0 :                 return false;
      99                 :            : 
     100                 :            :         /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with
     101                 :            :          * no caps field set. */
     102         [ -  + ]:         32 :         if (n->has_capabilities &&
     103         [ #  # ]:          0 :             (n->enabled_capabilities & lldp->capability_mask) == 0)
     104                 :          0 :                 return false;
     105                 :            : 
     106                 :            :         /* Keep everything else */
     107                 :         32 :         return true;
     108                 :            : }
     109                 :            : 
     110                 :            : static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor);
     111                 :            : 
     112                 :         32 : static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) {
     113                 :         32 :         _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL;
     114                 :            :         bool keep;
     115                 :            :         int r;
     116                 :            : 
     117         [ -  + ]:         32 :         assert(lldp);
     118         [ -  + ]:         32 :         assert(n);
     119         [ -  + ]:         32 :         assert(!n->lldp);
     120                 :            : 
     121                 :         32 :         keep = lldp_keep_neighbor(lldp, n);
     122                 :            : 
     123                 :            :         /* First retrieve the old entry for this MSAP */
     124                 :         32 :         old = hashmap_get(lldp->neighbor_by_id, &n->id);
     125         [ -  + ]:         32 :         if (old) {
     126                 :          0 :                 sd_lldp_neighbor_ref(old);
     127                 :            : 
     128         [ #  # ]:          0 :                 if (!keep) {
     129                 :          0 :                         lldp_neighbor_unlink(old);
     130                 :          0 :                         lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old);
     131                 :          0 :                         return 0;
     132                 :            :                 }
     133                 :            : 
     134         [ #  # ]:          0 :                 if (lldp_neighbor_equal(n, old)) {
     135                 :            :                         /* Is this equal, then restart the TTL counter, but don't do anything else. */
     136                 :          0 :                         old->timestamp = n->timestamp;
     137                 :          0 :                         lldp_start_timer(lldp, old);
     138                 :          0 :                         lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old);
     139                 :          0 :                         return 0;
     140                 :            :                 }
     141                 :            : 
     142                 :            :                 /* Data changed, remove the old entry, and add a new one */
     143                 :          0 :                 lldp_neighbor_unlink(old);
     144                 :            : 
     145         [ -  + ]:         32 :         } else if (!keep)
     146                 :          0 :                 return 0;
     147                 :            : 
     148                 :            :         /* Then, make room for at least one new neighbor */
     149                 :         32 :         lldp_make_space(lldp, 1);
     150                 :            : 
     151                 :         32 :         r = hashmap_put(lldp->neighbor_by_id, &n->id, n);
     152         [ -  + ]:         32 :         if (r < 0)
     153                 :          0 :                 goto finish;
     154                 :            : 
     155                 :         32 :         r = prioq_put(lldp->neighbor_by_expiry, n, &n->prioq_idx);
     156         [ -  + ]:         32 :         if (r < 0) {
     157         [ #  # ]:          0 :                 assert_se(hashmap_remove(lldp->neighbor_by_id, &n->id) == n);
     158                 :          0 :                 goto finish;
     159                 :            :         }
     160                 :            : 
     161                 :         32 :         n->lldp = lldp;
     162                 :            : 
     163                 :         32 :         lldp_start_timer(lldp, n);
     164         [ -  + ]:         32 :         lldp_callback(lldp, old ? SD_LLDP_EVENT_UPDATED : SD_LLDP_EVENT_ADDED, n);
     165                 :            : 
     166                 :         32 :         return 1;
     167                 :            : 
     168                 :          0 : finish:
     169         [ #  # ]:          0 :         if (old)
     170                 :          0 :                 lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old);
     171                 :            : 
     172                 :          0 :         return r;
     173                 :            : }
     174                 :            : 
     175                 :         36 : static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) {
     176                 :            :         int r;
     177                 :            : 
     178         [ -  + ]:         36 :         assert(lldp);
     179         [ -  + ]:         36 :         assert(n);
     180                 :            : 
     181                 :         36 :         r = lldp_neighbor_parse(n);
     182         [ +  + ]:         36 :         if (r == -EBADMSG) /* Ignore bad messages */
     183                 :          4 :                 return 0;
     184         [ -  + ]:         32 :         if (r < 0)
     185                 :          0 :                 return r;
     186                 :            : 
     187                 :         32 :         r = lldp_add_neighbor(lldp, n);
     188         [ -  + ]:         32 :         if (r < 0) {
     189                 :          0 :                 log_lldp_errno(r, "Failed to add datagram. Ignoring.");
     190                 :          0 :                 return 0;
     191                 :            :         }
     192                 :            : 
     193                 :         32 :         log_lldp("Successfully processed LLDP datagram.");
     194                 :         32 :         return 0;
     195                 :            : }
     196                 :            : 
     197                 :         36 : static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
     198                 :         36 :         _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
     199                 :            :         ssize_t space, length;
     200                 :         36 :         sd_lldp *lldp = userdata;
     201                 :            :         struct timespec ts;
     202                 :            : 
     203         [ -  + ]:         36 :         assert(fd >= 0);
     204         [ -  + ]:         36 :         assert(lldp);
     205                 :            : 
     206                 :         36 :         space = next_datagram_size_fd(fd);
     207         [ -  + ]:         36 :         if (space < 0)
     208                 :          0 :                 return log_lldp_errno(space, "Failed to determine datagram size to read: %m");
     209                 :            : 
     210                 :         36 :         n = lldp_neighbor_new(space);
     211         [ -  + ]:         36 :         if (!n)
     212                 :          0 :                 return -ENOMEM;
     213                 :            : 
     214                 :         36 :         length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
     215         [ -  + ]:         36 :         if (length < 0) {
     216   [ #  #  #  # ]:          0 :                 if (IN_SET(errno, EAGAIN, EINTR))
     217                 :          0 :                         return 0;
     218                 :            : 
     219                 :          0 :                 return log_lldp_errno(errno, "Failed to read LLDP datagram: %m");
     220                 :            :         }
     221                 :            : 
     222         [ -  + ]:         36 :         if ((size_t) length != n->raw_size) {
     223                 :          0 :                 log_lldp("Packet size mismatch.");
     224                 :          0 :                 return -EINVAL;
     225                 :            :         }
     226                 :            : 
     227                 :            :         /* Try to get the timestamp of this packet if it is known */
     228         [ -  + ]:         36 :         if (ioctl(fd, SIOCGSTAMPNS, &ts) >= 0)
     229                 :          0 :                 triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts));
     230                 :            :         else
     231                 :         36 :                 triple_timestamp_get(&n->timestamp);
     232                 :            : 
     233                 :         36 :         return lldp_handle_datagram(lldp, n);
     234                 :            : }
     235                 :            : 
     236                 :         32 : static void lldp_reset(sd_lldp *lldp) {
     237         [ -  + ]:         32 :         assert(lldp);
     238                 :            : 
     239                 :         32 :         (void) event_source_disable(lldp->timer_event_source);
     240                 :         32 :         lldp->io_event_source = sd_event_source_unref(lldp->io_event_source);
     241                 :         32 :         lldp->fd = safe_close(lldp->fd);
     242                 :         32 : }
     243                 :            : 
     244                 :         16 : _public_ int sd_lldp_start(sd_lldp *lldp) {
     245                 :            :         int r;
     246                 :            : 
     247   [ -  +  -  + ]:         16 :         assert_return(lldp, -EINVAL);
     248   [ -  +  -  + ]:         16 :         assert_return(lldp->event, -EINVAL);
     249   [ -  +  -  + ]:         16 :         assert_return(lldp->ifindex > 0, -EINVAL);
     250                 :            : 
     251         [ -  + ]:         16 :         if (lldp->fd >= 0)
     252                 :          0 :                 return 0;
     253                 :            : 
     254         [ -  + ]:         16 :         assert(!lldp->io_event_source);
     255                 :            : 
     256                 :         16 :         lldp->fd = lldp_network_bind_raw_socket(lldp->ifindex);
     257         [ -  + ]:         16 :         if (lldp->fd < 0)
     258                 :          0 :                 return lldp->fd;
     259                 :            : 
     260                 :         16 :         r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp);
     261         [ -  + ]:         16 :         if (r < 0)
     262                 :          0 :                 goto fail;
     263                 :            : 
     264                 :         16 :         r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority);
     265         [ -  + ]:         16 :         if (r < 0)
     266                 :          0 :                 goto fail;
     267                 :            : 
     268                 :         16 :         (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io");
     269                 :            : 
     270                 :         16 :         log_lldp("Started LLDP client");
     271                 :         16 :         return 1;
     272                 :            : 
     273                 :          0 : fail:
     274                 :          0 :         lldp_reset(lldp);
     275                 :          0 :         return r;
     276                 :            : }
     277                 :            : 
     278                 :         16 : _public_ int sd_lldp_stop(sd_lldp *lldp) {
     279   [ -  +  -  + ]:         16 :         assert_return(lldp, -EINVAL);
     280                 :            : 
     281         [ -  + ]:         16 :         if (lldp->fd < 0)
     282                 :          0 :                 return 0;
     283                 :            : 
     284                 :         16 :         log_lldp("Stopping LLDP client");
     285                 :            : 
     286                 :         16 :         lldp_reset(lldp);
     287                 :         16 :         lldp_flush_neighbors(lldp);
     288                 :            : 
     289                 :         16 :         return 1;
     290                 :            : }
     291                 :            : 
     292                 :         16 : _public_ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) {
     293                 :            :         int r;
     294                 :            : 
     295   [ -  +  -  + ]:         16 :         assert_return(lldp, -EINVAL);
     296   [ -  +  -  + ]:         16 :         assert_return(lldp->fd < 0, -EBUSY);
     297   [ -  +  -  + ]:         16 :         assert_return(!lldp->event, -EBUSY);
     298                 :            : 
     299         [ +  - ]:         16 :         if (event)
     300                 :         16 :                 lldp->event = sd_event_ref(event);
     301                 :            :         else {
     302                 :          0 :                 r = sd_event_default(&lldp->event);
     303         [ #  # ]:          0 :                 if (r < 0)
     304                 :          0 :                         return r;
     305                 :            :         }
     306                 :            : 
     307                 :         16 :         lldp->event_priority = priority;
     308                 :            : 
     309                 :         16 :         return 0;
     310                 :            : }
     311                 :            : 
     312                 :         32 : _public_ int sd_lldp_detach_event(sd_lldp *lldp) {
     313                 :            : 
     314   [ -  +  -  + ]:         32 :         assert_return(lldp, -EINVAL);
     315   [ -  +  -  + ]:         32 :         assert_return(lldp->fd < 0, -EBUSY);
     316                 :            : 
     317                 :         32 :         lldp->event = sd_event_unref(lldp->event);
     318                 :         32 :         return 0;
     319                 :            : }
     320                 :            : 
     321                 :          0 : _public_ sd_event* sd_lldp_get_event(sd_lldp *lldp) {
     322   [ #  #  #  # ]:          0 :         assert_return(lldp, NULL);
     323                 :            : 
     324                 :          0 :         return lldp->event;
     325                 :            : }
     326                 :            : 
     327                 :         16 : _public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) {
     328   [ -  +  -  + ]:         16 :         assert_return(lldp, -EINVAL);
     329                 :            : 
     330                 :         16 :         lldp->callback = cb;
     331                 :         16 :         lldp->userdata = userdata;
     332                 :            : 
     333                 :         16 :         return 0;
     334                 :            : }
     335                 :            : 
     336                 :         16 : _public_ int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) {
     337   [ -  +  -  + ]:         16 :         assert_return(lldp, -EINVAL);
     338   [ -  +  -  + ]:         16 :         assert_return(ifindex > 0, -EINVAL);
     339   [ -  +  -  + ]:         16 :         assert_return(lldp->fd < 0, -EBUSY);
     340                 :            : 
     341                 :         16 :         lldp->ifindex = ifindex;
     342                 :         16 :         return 0;
     343                 :            : }
     344                 :            : 
     345                 :         16 : static sd_lldp* lldp_free(sd_lldp *lldp) {
     346         [ -  + ]:         16 :         assert(lldp);
     347                 :            : 
     348                 :         16 :         lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source);
     349                 :            : 
     350                 :         16 :         lldp_reset(lldp);
     351                 :         16 :         sd_lldp_detach_event(lldp);
     352                 :         16 :         lldp_flush_neighbors(lldp);
     353                 :            : 
     354                 :         16 :         hashmap_free(lldp->neighbor_by_id);
     355                 :         16 :         prioq_free(lldp->neighbor_by_expiry);
     356                 :         16 :         return mfree(lldp);
     357                 :            : }
     358                 :            : 
     359   [ +  +  -  +  :         44 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp, sd_lldp, lldp_free);
                   -  + ]
     360                 :            : 
     361                 :         16 : _public_ int sd_lldp_new(sd_lldp **ret) {
     362                 :         16 :         _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL;
     363                 :            :         int r;
     364                 :            : 
     365   [ -  +  -  + ]:         16 :         assert_return(ret, -EINVAL);
     366                 :            : 
     367                 :         16 :         lldp = new(sd_lldp, 1);
     368         [ -  + ]:         16 :         if (!lldp)
     369                 :          0 :                 return -ENOMEM;
     370                 :            : 
     371                 :         16 :         *lldp = (sd_lldp) {
     372                 :            :                 .n_ref = 1,
     373                 :            :                 .fd = -1,
     374                 :            :                 .neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX,
     375                 :            :                 .capability_mask = (uint16_t) -1,
     376                 :            :         };
     377                 :            : 
     378                 :         16 :         lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_hash_ops);
     379         [ -  + ]:         16 :         if (!lldp->neighbor_by_id)
     380                 :          0 :                 return -ENOMEM;
     381                 :            : 
     382                 :         16 :         r = prioq_ensure_allocated(&lldp->neighbor_by_expiry, lldp_neighbor_prioq_compare_func);
     383         [ -  + ]:         16 :         if (r < 0)
     384                 :          0 :                 return r;
     385                 :            : 
     386                 :         16 :         *ret = TAKE_PTR(lldp);
     387                 :            : 
     388                 :         16 :         return 0;
     389                 :            : }
     390                 :            : 
     391                 :         40 : static int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) {
     392                 :         40 :         return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
     393                 :            : }
     394                 :            : 
     395                 :          0 : static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
     396                 :          0 :         sd_lldp *lldp = userdata;
     397                 :            :         int r;
     398                 :            : 
     399                 :          0 :         r = lldp_make_space(lldp, 0);
     400         [ #  # ]:          0 :         if (r < 0)
     401                 :          0 :                 return log_lldp_errno(r, "Failed to make space: %m");
     402                 :            : 
     403                 :          0 :         r = lldp_start_timer(lldp, NULL);
     404         [ #  # ]:          0 :         if (r < 0)
     405                 :          0 :                 return log_lldp_errno(r, "Failed to restart timer: %m");
     406                 :            : 
     407                 :          0 :         return 0;
     408                 :            : }
     409                 :            : 
     410                 :         44 : static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) {
     411                 :            :         sd_lldp_neighbor *n;
     412                 :            : 
     413         [ -  + ]:         44 :         assert(lldp);
     414                 :            : 
     415         [ +  + ]:         44 :         if (neighbor)
     416                 :         32 :                 lldp_neighbor_start_ttl(neighbor);
     417                 :            : 
     418                 :         44 :         n = prioq_peek(lldp->neighbor_by_expiry);
     419         [ -  + ]:         44 :         if (!n)
     420                 :          0 :                 return event_source_disable(lldp->timer_event_source);
     421                 :            : 
     422         [ -  + ]:         44 :         if (!lldp->event)
     423                 :          0 :                 return 0;
     424                 :            : 
     425                 :         44 :         return event_reset_time(lldp->event, &lldp->timer_event_source,
     426                 :            :                                 clock_boottime_or_monotonic(),
     427                 :            :                                 n->until, 0,
     428                 :            :                                 on_timer_event, lldp,
     429                 :            :                                 lldp->event_priority, "lldp-timer", true);
     430                 :            : }
     431                 :            : 
     432                 :         16 : _public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) {
     433                 :         16 :         sd_lldp_neighbor **l = NULL, *n;
     434                 :            :         Iterator i;
     435                 :         16 :         int k = 0, r;
     436                 :            : 
     437   [ -  +  -  + ]:         16 :         assert_return(lldp, -EINVAL);
     438   [ -  +  -  + ]:         16 :         assert_return(ret, -EINVAL);
     439                 :            : 
     440         [ +  + ]:         16 :         if (hashmap_isempty(lldp->neighbor_by_id)) { /* Special shortcut */
     441                 :          4 :                 *ret = NULL;
     442                 :          4 :                 return 0;
     443                 :            :         }
     444                 :            : 
     445         [ +  - ]:         12 :         l = new0(sd_lldp_neighbor*, hashmap_size(lldp->neighbor_by_id));
     446         [ -  + ]:         12 :         if (!l)
     447                 :          0 :                 return -ENOMEM;
     448                 :            : 
     449                 :         12 :         r = lldp_start_timer(lldp, NULL);
     450         [ -  + ]:         12 :         if (r < 0) {
     451                 :          0 :                 free(l);
     452                 :          0 :                 return r;
     453                 :            :         }
     454                 :            : 
     455         [ +  + ]:         44 :         HASHMAP_FOREACH(n, lldp->neighbor_by_id, i)
     456                 :         32 :                 l[k++] = sd_lldp_neighbor_ref(n);
     457                 :            : 
     458         [ -  + ]:         12 :         assert((size_t) k == hashmap_size(lldp->neighbor_by_id));
     459                 :            : 
     460                 :            :         /* Return things in a stable order */
     461                 :         12 :         typesafe_qsort(l, k, neighbor_compare_func);
     462                 :         12 :         *ret = l;
     463                 :            : 
     464                 :         12 :         return k;
     465                 :            : }
     466                 :            : 
     467                 :          0 : _public_ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t m) {
     468   [ #  #  #  # ]:          0 :         assert_return(lldp, -EINVAL);
     469   [ #  #  #  # ]:          0 :         assert_return(m <= 0, -EINVAL);
     470                 :            : 
     471                 :          0 :         lldp->neighbors_max = m;
     472                 :          0 :         lldp_make_space(lldp, 0);
     473                 :            : 
     474                 :          0 :         return 0;
     475                 :            : }
     476                 :            : 
     477                 :          0 : _public_ int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask) {
     478   [ #  #  #  # ]:          0 :         assert_return(lldp, -EINVAL);
     479   [ #  #  #  # ]:          0 :         assert_return(mask != 0, -EINVAL);
     480                 :            : 
     481                 :          0 :         lldp->capability_mask = mask;
     482                 :            : 
     483                 :          0 :         return 0;
     484                 :            : }
     485                 :            : 
     486                 :          0 : _public_ int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *addr) {
     487   [ #  #  #  # ]:          0 :         assert_return(lldp, -EINVAL);
     488                 :            : 
     489                 :            :         /* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so
     490                 :            :          * that our own can be filtered out here. */
     491                 :            : 
     492         [ #  # ]:          0 :         if (addr)
     493                 :          0 :                 lldp->filter_address = *addr;
     494                 :            :         else
     495         [ #  # ]:          0 :                 zero(lldp->filter_address);
     496                 :            : 
     497                 :          0 :         return 0;
     498                 :            : }

Generated by: LCOV version 1.14