LCOV - code coverage report
Current view: top level - libsystemd-network - sd-lldp.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 3 322 0.9 %
Date: 2015-07-29 18:47:03 Functions: 1 17 5.9 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :     This file is part of systemd.
       5             : 
       6             :     Copyright (C) 2014 Tom Gundersen
       7             :     Copyright (C) 2014 Susant Sahani
       8             : 
       9             :     systemd is free software; you can redistribute it and/or modify it
      10             :     under the terms of the GNU Lesser General Public License as published by
      11             :     the Free Software Foundation; either version 2.1 of the License, or
      12             :     (at your option) any later version.
      13             : 
      14             :     systemd is distributed in the hope that it will be useful, but
      15             :     WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      17             :     Lesser General Public License for more details.
      18             : 
      19             :     You should have received a copy of the GNU Lesser General Public License
      20             :     along with systemd; If not, see <http://www.gnu.org/licenses/>.
      21             : ***/
      22             : 
      23             : #include <arpa/inet.h>
      24             : 
      25             : #include "siphash24.h"
      26             : #include "hashmap.h"
      27             : 
      28             : #include "lldp-tlv.h"
      29             : #include "lldp-port.h"
      30             : #include "sd-lldp.h"
      31             : #include "prioq.h"
      32             : #include "lldp-internal.h"
      33             : #include "lldp-util.h"
      34             : 
      35             : typedef enum LLDPAgentRXState {
      36             :         LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4,
      37             :         LLDP_AGENT_RX_DELETE_AGED_INFO,
      38             :         LLDP_AGENT_RX_LLDP_INITIALIZE,
      39             :         LLDP_AGENT_RX_WAIT_FOR_FRAME,
      40             :         LLDP_AGENT_RX_RX_FRAME,
      41             :         LLDP_AGENT_RX_DELETE_INFO,
      42             :         LLDP_AGENT_RX_UPDATE_INFO,
      43             :         _LLDP_AGENT_RX_STATE_MAX,
      44             :         _LLDP_AGENT_RX_INVALID = -1,
      45             : } LLDPAgentRXState;
      46             : 
      47             : /* Section 10.5.2.2 Reception counters */
      48             : struct lldp_agent_statistics {
      49             :         uint64_t stats_ageouts_total;
      50             :         uint64_t stats_frames_discarded_total;
      51             :         uint64_t stats_frames_in_errors_total;
      52             :         uint64_t stats_frames_in_total;
      53             :         uint64_t stats_tlvs_discarded_total;
      54             :         uint64_t stats_tlvs_unrecognized_total;
      55             : };
      56             : 
      57             : struct sd_lldp {
      58             :         lldp_port *port;
      59             : 
      60             :         Prioq *by_expiry;
      61             :         Hashmap *neighbour_mib;
      62             : 
      63             :         sd_lldp_cb_t cb;
      64             : 
      65             :         void *userdata;
      66             : 
      67             :         LLDPAgentRXState rx_state;
      68             :         lldp_agent_statistics statistics;
      69             : };
      70             : 
      71           0 : static unsigned long chassis_id_hash_func(const void *p,
      72             :                                           const uint8_t hash_key[HASH_KEY_SIZE]) {
      73             :         uint64_t u;
      74           0 :         const lldp_chassis_id *id = p;
      75             : 
      76           0 :         assert(id);
      77             : 
      78           0 :         siphash24((uint8_t *) &u, id->data, id->length, hash_key);
      79             : 
      80           0 :         return (unsigned long) u;
      81             : }
      82             : 
      83           0 : static int chassis_id_compare_func(const void *_a, const void *_b) {
      84             :         const lldp_chassis_id *a, *b;
      85             : 
      86           0 :         a = _a;
      87           0 :         b = _b;
      88             : 
      89           0 :         assert(!a->length || a->data);
      90           0 :         assert(!b->length || b->data);
      91             : 
      92           0 :         if (a->type != b->type)
      93           0 :                 return -1;
      94             : 
      95           0 :         if (a->length != b->length)
      96           0 :                 return a->length < b->length ? -1 : 1;
      97             : 
      98           0 :         return memcmp(a->data, b->data, a->length);
      99             : }
     100             : 
     101             : static const struct hash_ops chassis_id_hash_ops = {
     102             :         .hash = chassis_id_hash_func,
     103             :         .compare = chassis_id_compare_func
     104             : };
     105             : 
     106             : static void lldp_mib_delete_objects(sd_lldp *lldp);
     107             : static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state);
     108             : static void lldp_run_state_machine(sd_lldp *ll);
     109             : 
     110           0 : static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) {
     111             :         int r;
     112             : 
     113           0 :         assert(lldp);
     114           0 :         assert(tlv);
     115             : 
     116             :         /* Remove expired packets */
     117           0 :         if (prioq_size(lldp->by_expiry) > 0) {
     118             : 
     119           0 :                 lldp_set_state(lldp, LLDP_AGENT_RX_DELETE_INFO);
     120             : 
     121           0 :                 lldp_mib_delete_objects(lldp);
     122             :         }
     123             : 
     124           0 :         r = lldp_mib_add_objects(lldp->by_expiry, lldp->neighbour_mib, tlv);
     125           0 :         if (r < 0)
     126           0 :                 goto out;
     127             : 
     128           0 :         lldp_set_state(lldp, LLDP_AGENT_RX_UPDATE_INFO);
     129             : 
     130           0 :         log_lldp("Packet added. MIB size: %d , PQ size: %d",
     131             :                  hashmap_size(lldp->neighbour_mib),
     132             :                  prioq_size(lldp->by_expiry));
     133             : 
     134           0 :         lldp->statistics.stats_frames_in_total ++;
     135             : 
     136             :  out:
     137           0 :         if (r < 0)
     138           0 :                 log_lldp("Receive frame failed: %s", strerror(-r));
     139             : 
     140           0 :         lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
     141             : 
     142           0 :         return 0;
     143             : }
     144             : 
     145             : /* 10.3.2 LLDPDU validation: rxProcessFrame() */
     146           0 : int lldp_handle_packet(tlv_packet *tlv, uint16_t length) {
     147             :         uint16_t type, len, i, l, t;
     148           0 :         bool chassis_id = false;
     149           0 :         bool malformed = false;
     150           0 :         bool port_id = false;
     151           0 :         bool ttl = false;
     152           0 :         bool end = false;
     153             :         lldp_port *port;
     154             :         uint8_t *p, *q;
     155             :         sd_lldp *lldp;
     156             :         int r;
     157             : 
     158           0 :         assert(tlv);
     159           0 :         assert(length > 0);
     160             : 
     161           0 :         port = (lldp_port *) tlv->userdata;
     162           0 :         lldp = (sd_lldp *) port->userdata;
     163             : 
     164           0 :         if (lldp->port->status == LLDP_PORT_STATUS_DISABLED) {
     165           0 :                 log_lldp("Port is disabled : %s . Dropping ...",
     166             :                          lldp->port->ifname);
     167           0 :                 goto out;
     168             :         }
     169             : 
     170           0 :         lldp_set_state(lldp, LLDP_AGENT_RX_RX_FRAME);
     171             : 
     172           0 :         p = tlv->pdu;
     173           0 :         p += sizeof(struct ether_header);
     174             : 
     175           0 :         for (i = 1, l = 0; l <= length; i++) {
     176             : 
     177           0 :                 memcpy(&t, p, sizeof(uint16_t));
     178             : 
     179           0 :                 type = ntohs(t) >> 9;
     180           0 :                 len = ntohs(t) & 0x01ff;
     181             : 
     182           0 :                 if (type == LLDP_TYPE_END) {
     183           0 :                         if (len != 0) {
     184           0 :                                 log_lldp("TLV type end is not length 0. Length:%d received . Dropping ...",
     185             :                                          len);
     186             : 
     187           0 :                                 malformed = true;
     188           0 :                                 goto out;
     189             :                         }
     190             : 
     191           0 :                         end = true;
     192             : 
     193           0 :                         break;
     194           0 :                 } else if (type >=_LLDP_TYPE_MAX) {
     195           0 :                         log_lldp("TLV type not recognized %d . Dropping ...",
     196             :                                  type);
     197             : 
     198           0 :                         malformed = true;
     199           0 :                         goto out;
     200             :                 }
     201             : 
     202             :                 /* skip type and lengh encoding */
     203           0 :                 p += 2;
     204           0 :                 q = p;
     205             : 
     206           0 :                 p += len;
     207           0 :                 l += (len + 2);
     208             : 
     209           0 :                 if (i <= 3) {
     210           0 :                         if (i != type) {
     211           0 :                                 log_lldp("TLV missing or out of order. Dropping ...");
     212             : 
     213           0 :                                 malformed = true;
     214           0 :                                 goto out;
     215             :                         }
     216             :                 }
     217             : 
     218           0 :                 switch(type) {
     219             :                 case LLDP_TYPE_CHASSIS_ID:
     220             : 
     221           0 :                         if (len < 2) {
     222           0 :                                 log_lldp("Received malformed Chassis ID TLV len = %d. Dropping",
     223             :                                          len);
     224             : 
     225           0 :                                 malformed = true;
     226           0 :                                 goto out;
     227             :                         }
     228             : 
     229           0 :                         if (chassis_id) {
     230           0 :                                 log_lldp("Duplicate Chassis ID TLV found. Dropping ...");
     231             : 
     232           0 :                                 malformed = true;
     233           0 :                                 goto out;
     234             :                         }
     235             : 
     236             :                         /* Look what subtype it has */
     237           0 :                         if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED ||
     238           0 :                             *q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) {
     239           0 :                                 log_lldp("Unknown subtype: %d found in Chassis ID TLV . Dropping ...",
     240             :                                          *q);
     241             : 
     242           0 :                                 malformed = true;
     243           0 :                                 goto out;
     244             : 
     245             :                         }
     246             : 
     247           0 :                         chassis_id = true;
     248             : 
     249           0 :                         break;
     250             :                 case LLDP_TYPE_PORT_ID:
     251             : 
     252           0 :                         if (len < 2) {
     253           0 :                                 log_lldp("Received malformed Port ID TLV len = %d. Dropping",
     254             :                                          len);
     255             : 
     256           0 :                                 malformed = true;
     257           0 :                                 goto out;
     258             :                         }
     259             : 
     260           0 :                         if (port_id) {
     261           0 :                                 log_lldp("Duplicate Port ID TLV found. Dropping ...");
     262             : 
     263           0 :                                 malformed = true;
     264           0 :                                 goto out;
     265             :                         }
     266             : 
     267             :                         /* Look what subtype it has */
     268           0 :                         if (*q == LLDP_PORT_SUBTYPE_RESERVED ||
     269           0 :                             *q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) {
     270           0 :                                 log_lldp("Unknown subtype: %d found in Port ID TLV . Dropping ...",
     271             :                                          *q);
     272             : 
     273           0 :                                 malformed = true;
     274           0 :                                 goto out;
     275             : 
     276             :                         }
     277             : 
     278           0 :                         port_id = true;
     279             : 
     280           0 :                         break;
     281             :                 case LLDP_TYPE_TTL:
     282             : 
     283           0 :                         if(len != 2) {
     284           0 :                                 log_lldp(
     285             :                                          "Received invalid lenth: %d TTL TLV. Dropping ...",
     286             :                                          len);
     287             : 
     288           0 :                                 malformed = true;
     289           0 :                                 goto out;
     290             :                         }
     291             : 
     292           0 :                         if (ttl) {
     293           0 :                                 log_lldp("Duplicate TTL TLV found. Dropping ...");
     294             : 
     295           0 :                                 malformed = true;
     296           0 :                                 goto out;
     297             :                         }
     298             : 
     299           0 :                         ttl = true;
     300             : 
     301           0 :                         break;
     302             :                 default:
     303             : 
     304           0 :                         if (len == 0) {
     305           0 :                                 log_lldp("TLV type = %d's, length 0 received . Dropping ...",
     306             :                                          type);
     307             : 
     308           0 :                                 malformed = true;
     309           0 :                                 goto out;
     310             :                         }
     311           0 :                         break;
     312             :                 }
     313             :         }
     314             : 
     315           0 :         if(!chassis_id || !port_id || !ttl || !end) {
     316           0 :                 log_lldp( "One or more mandotory TLV missing . Dropping ...");
     317             : 
     318           0 :                 malformed = true;
     319           0 :                 goto out;
     320             : 
     321             :         }
     322             : 
     323           0 :         r = tlv_packet_parse_pdu(tlv, length);
     324           0 :         if (r < 0) {
     325           0 :                 log_lldp( "Failed to parse the TLV. Dropping ...");
     326             : 
     327           0 :                 malformed = true;
     328           0 :                 goto out;
     329             :         }
     330             : 
     331           0 :         return lldp_receive_frame(lldp, tlv);
     332             : 
     333             :  out:
     334           0 :         lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
     335             : 
     336           0 :         if (malformed) {
     337           0 :                 lldp->statistics.stats_frames_discarded_total ++;
     338           0 :                 lldp->statistics.stats_frames_in_errors_total ++;
     339             :         }
     340             : 
     341           0 :         tlv_packet_free(tlv);
     342             : 
     343           0 :         return 0;
     344             : }
     345             : 
     346           0 : static int ttl_expiry_item_prioq_compare_func(const void *a, const void *b) {
     347           0 :         const lldp_neighbour_port *p = a, *q = b;
     348             : 
     349           0 :         if (p->until < q->until)
     350           0 :                 return -1;
     351             : 
     352           0 :         if (p->until > q->until)
     353           0 :                 return 1;
     354             : 
     355           0 :         return 0;
     356             : }
     357             : 
     358           0 : static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state) {
     359             : 
     360           0 :         assert(lldp);
     361           0 :         assert(state < _LLDP_AGENT_RX_STATE_MAX);
     362             : 
     363           0 :         lldp->rx_state = state;
     364             : 
     365           0 :         lldp_run_state_machine(lldp);
     366           0 : }
     367             : 
     368           0 : static void lldp_run_state_machine(sd_lldp *lldp) {
     369             : 
     370           0 :         if (lldp->rx_state == LLDP_AGENT_RX_UPDATE_INFO)
     371           0 :                 if (lldp->cb)
     372           0 :                         lldp->cb(lldp, LLDP_AGENT_RX_UPDATE_INFO, lldp->userdata);
     373           0 : }
     374             : 
     375             : /* 10.5.5.2.1 mibDeleteObjects ()
     376             :  * The mibDeleteObjects () procedure deletes all information in the LLDP remote
     377             :  * systems MIB associated with the MSAP identifier if an LLDPDU is received with
     378             :  * an rxTTL value of zero (see 10.3.2) or the timing counter rxInfoTTL expires. */
     379             : 
     380           0 : static void lldp_mib_delete_objects(sd_lldp *lldp) {
     381             :         lldp_neighbour_port *p;
     382           0 :         usec_t t = 0;
     383             : 
     384             :         /* Remove all entries that are past their TTL */
     385             :         for (;;) {
     386             : 
     387           0 :                 if (prioq_size(lldp->by_expiry) <= 0)
     388           0 :                         break;
     389             : 
     390           0 :                 p = prioq_peek(lldp->by_expiry);
     391           0 :                 if (!p)
     392           0 :                         break;
     393             : 
     394           0 :                 if (t <= 0)
     395           0 :                         t = now(CLOCK_BOOTTIME);
     396             : 
     397           0 :                 if (p->until > t)
     398           0 :                         break;
     399             : 
     400           0 :                 lldp_neighbour_port_remove_and_free(p);
     401             : 
     402           0 :                 lldp->statistics.stats_ageouts_total ++;
     403           0 :         }
     404           0 : }
     405             : 
     406           0 : static void lldp_mib_objects_flush(sd_lldp *lldp) {
     407             :         lldp_neighbour_port *p, *q;
     408             :         lldp_chassis *c;
     409             : 
     410           0 :         assert(lldp);
     411           0 :         assert(lldp->neighbour_mib);
     412           0 :         assert(lldp->by_expiry);
     413             : 
     414             :         /* Drop all packets */
     415           0 :         while ((c = hashmap_steal_first(lldp->neighbour_mib))) {
     416             : 
     417           0 :                 LIST_FOREACH_SAFE(port, p, q, c->ports) {
     418           0 :                         lldp_neighbour_port_remove_and_free(p);
     419             :                 }
     420             :         }
     421             : 
     422           0 :         assert(hashmap_size(lldp->neighbour_mib) == 0);
     423           0 :         assert(prioq_size(lldp->by_expiry) == 0);
     424           0 : }
     425             : 
     426           0 : int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
     427           0 :         _cleanup_free_ char *temp_path = NULL;
     428           0 :         _cleanup_fclose_ FILE *f = NULL;
     429             :         uint8_t *mac, *port_id, type;
     430             :         lldp_neighbour_port *p;
     431           0 :         uint16_t data = 0, length = 0;
     432             :         char buf[LINE_MAX];
     433             :         lldp_chassis *c;
     434             :         usec_t time;
     435             :         Iterator i;
     436             :         int r;
     437             : 
     438           0 :         assert(lldp);
     439           0 :         assert(lldp_file);
     440             : 
     441           0 :         r = fopen_temporary(lldp_file, &f, &temp_path);
     442           0 :         if (r < 0)
     443           0 :                 goto finish;
     444             : 
     445           0 :         fchmod(fileno(f), 0644);
     446             : 
     447           0 :         HASHMAP_FOREACH(c, lldp->neighbour_mib, i) {
     448           0 :                 LIST_FOREACH(port, p, c->ports) {
     449           0 :                         _cleanup_free_ char *s = NULL;
     450             :                         char *k, *t;
     451             : 
     452           0 :                         r = lldp_read_chassis_id(p->packet, &type, &length, &mac);
     453           0 :                         if (r < 0)
     454           0 :                                 continue;
     455             : 
     456           0 :                         sprintf(buf, "'_Chassis=%02x:%02x:%02x:%02x:%02x:%02x' '_CType=%d' ",
     457           0 :                                 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type);
     458             : 
     459           0 :                         s = strdup(buf);
     460           0 :                         if (!s)
     461           0 :                                 return -ENOMEM;
     462             : 
     463           0 :                         r = lldp_read_port_id(p->packet, &type, &length, &port_id);
     464           0 :                         if (r < 0)
     465           0 :                                 continue;
     466             : 
     467           0 :                         if (type != LLDP_PORT_SUBTYPE_MAC_ADDRESS) {
     468           0 :                                 k = strndup((char *) port_id, length -1);
     469           0 :                                 if (!k)
     470           0 :                                         return -ENOMEM;
     471             : 
     472           0 :                                 sprintf(buf, "'_Port=%s' '_PType=%d' ", k , type);
     473           0 :                                 free(k);
     474             :                         } else {
     475           0 :                                 mac = port_id;
     476           0 :                                 sprintf(buf, "'_Port=%02x:%02x:%02x:%02x:%02x:%02x' '_PType=%d' ",
     477           0 :                                         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type);
     478             :                         }
     479             : 
     480           0 :                         k = strappend(s, buf);
     481           0 :                         if (!k)
     482           0 :                                 return -ENOMEM;
     483             : 
     484           0 :                         free(s);
     485           0 :                         s = k;
     486             : 
     487           0 :                         time = now(CLOCK_BOOTTIME);
     488             : 
     489             :                         /* Don't write expired packets */
     490           0 :                         if (time - p->until <= 0)
     491           0 :                                 continue;
     492             : 
     493           0 :                         sprintf(buf, "'_TTL="USEC_FMT"' ", p->until);
     494             : 
     495           0 :                         k = strappend(s, buf);
     496           0 :                         if (!k)
     497           0 :                                 return -ENOMEM;
     498             : 
     499           0 :                         free(s);
     500           0 :                         s = k;
     501             : 
     502           0 :                         r = lldp_read_system_name(p->packet, &length, &k);
     503           0 :                         if (r < 0)
     504           0 :                                 k = strappend(s, "'_NAME=N/A' ");
     505             :                         else {
     506           0 :                                 t = strndup(k, length);
     507           0 :                                 if (!t)
     508           0 :                                         return -ENOMEM;
     509             : 
     510           0 :                                 k = strjoin(s, "'_NAME=", t, "' ", NULL);
     511           0 :                                 free(t);
     512             :                         }
     513             : 
     514           0 :                         if (!k)
     515           0 :                                 return -ENOMEM;
     516             : 
     517           0 :                         free(s);
     518           0 :                         s = k;
     519             : 
     520           0 :                         (void) lldp_read_system_capability(p->packet, &data);
     521             : 
     522           0 :                         sprintf(buf, "'_CAP=%x'", data);
     523             : 
     524           0 :                         k = strappend(s, buf);
     525           0 :                         if (!k)
     526           0 :                                 return -ENOMEM;
     527             : 
     528           0 :                         free(s);
     529           0 :                         s = k;
     530             : 
     531           0 :                         fprintf(f, "%s\n", s);
     532             :                 }
     533             :         }
     534           0 :         r = 0;
     535             : 
     536           0 :         fflush(f);
     537             : 
     538           0 :         if (ferror(f) || rename(temp_path, lldp_file) < 0) {
     539           0 :                 r = -errno;
     540           0 :                 unlink(lldp_file);
     541           0 :                 unlink(temp_path);
     542             :         }
     543             : 
     544             :  finish:
     545           0 :         if (r < 0)
     546           0 :                 log_error("Failed to save lldp data %s: %s", lldp_file, strerror(-r));
     547             : 
     548           0 :         return r;
     549             : }
     550             : 
     551           0 : int sd_lldp_start(sd_lldp *lldp) {
     552             :         int r;
     553             : 
     554           0 :         assert_return(lldp, -EINVAL);
     555           0 :         assert_return(lldp->port, -EINVAL);
     556             : 
     557           0 :         lldp->port->status = LLDP_PORT_STATUS_ENABLED;
     558             : 
     559           0 :         lldp_set_state(lldp, LLDP_AGENT_RX_LLDP_INITIALIZE);
     560             : 
     561           0 :         r = lldp_port_start(lldp->port);
     562           0 :         if (r < 0) {
     563           0 :                 log_lldp("Failed to start Port : %s , %s",
     564             :                          lldp->port->ifname,
     565             :                          strerror(-r));
     566             : 
     567           0 :                 lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL);
     568             : 
     569           0 :                 return r;
     570             :         }
     571             : 
     572           0 :         lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
     573             : 
     574           0 :         return 0;
     575             : }
     576             : 
     577           0 : int sd_lldp_stop(sd_lldp *lldp) {
     578             :         int r;
     579             : 
     580           0 :         assert_return(lldp, -EINVAL);
     581           0 :         assert_return(lldp->port, -EINVAL);
     582             : 
     583           0 :         lldp->port->status = LLDP_PORT_STATUS_DISABLED;
     584             : 
     585           0 :         r = lldp_port_stop(lldp->port);
     586           0 :         if (r < 0)
     587           0 :                 return r;
     588             : 
     589           0 :         lldp_mib_objects_flush(lldp);
     590             : 
     591           0 :         return 0;
     592             : }
     593             : 
     594           0 : int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority) {
     595             :         int r;
     596             : 
     597           0 :         assert_return(lldp, -EINVAL);
     598           0 :         assert_return(!lldp->port->event, -EBUSY);
     599             : 
     600           0 :         if (event)
     601           0 :                 lldp->port->event = sd_event_ref(event);
     602             :         else {
     603           0 :                 r = sd_event_default(&lldp->port->event);
     604           0 :                 if (r < 0)
     605           0 :                         return r;
     606             :         }
     607             : 
     608           0 :         lldp->port->event_priority = priority;
     609             : 
     610           0 :         return 0;
     611             : }
     612             : 
     613           0 : int sd_lldp_detach_event(sd_lldp *lldp) {
     614             : 
     615           0 :         assert_return(lldp, -EINVAL);
     616             : 
     617           0 :         lldp->port->event = sd_event_unref(lldp->port->event);
     618             : 
     619           0 :         return 0;
     620             : }
     621             : 
     622           0 : int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata) {
     623           0 :         assert_return(lldp, -EINVAL);
     624             : 
     625           0 :         lldp->cb = cb;
     626           0 :         lldp->userdata = userdata;
     627             : 
     628           0 :         return 0;
     629             : }
     630             : 
     631           4 : void sd_lldp_free(sd_lldp *lldp) {
     632             : 
     633           4 :         if (!lldp)
     634           4 :                 return;
     635             : 
     636             :         /* Drop all packets */
     637           0 :         lldp_mib_objects_flush(lldp);
     638             : 
     639           0 :         lldp_port_free(lldp->port);
     640             : 
     641           0 :         hashmap_free(lldp->neighbour_mib);
     642           0 :         prioq_free(lldp->by_expiry);
     643             : 
     644           0 :         free(lldp);
     645             : }
     646             : 
     647           0 : int sd_lldp_new(int ifindex,
     648             :                 const char *ifname,
     649             :                 const struct ether_addr *mac,
     650             :                 sd_lldp **ret) {
     651           0 :         _cleanup_lldp_free_ sd_lldp *lldp = NULL;
     652             :         int r;
     653             : 
     654           0 :         assert_return(ret, -EINVAL);
     655           0 :         assert_return(ifindex > 0, -EINVAL);
     656           0 :         assert_return(ifname, -EINVAL);
     657           0 :         assert_return(mac, -EINVAL);
     658             : 
     659           0 :         lldp = new0(sd_lldp, 1);
     660           0 :         if (!lldp)
     661           0 :                 return -ENOMEM;
     662             : 
     663           0 :         r = lldp_port_new(ifindex, ifname, mac, lldp, &lldp->port);
     664           0 :         if (r < 0)
     665           0 :                 return r;
     666             : 
     667           0 :         lldp->neighbour_mib = hashmap_new(&chassis_id_hash_ops);
     668           0 :         if (!lldp->neighbour_mib)
     669           0 :                 return -ENOMEM;
     670             : 
     671           0 :         r = prioq_ensure_allocated(&lldp->by_expiry,
     672             :                                    ttl_expiry_item_prioq_compare_func);
     673           0 :         if (r < 0)
     674           0 :                 return r;
     675             : 
     676           0 :         lldp->rx_state = LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL;
     677             : 
     678           0 :         *ret = lldp;
     679           0 :         lldp = NULL;
     680             : 
     681           0 :         return 0;
     682             : }

Generated by: LCOV version 1.11