LCOV - code coverage report
Current view: top level - libsystemd-network - lldp-internal.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 249 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 15 0.0 %

          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 "lldp-internal.h"
      24             : 
      25             : /* We store maximum 1K chassis entries */
      26             : #define LLDP_MIB_MAX_CHASSIS 1024
      27             : 
      28             : /* Maximum Ports can be attached to any chassis */
      29             : #define LLDP_MIB_MAX_PORT_PER_CHASSIS 32
      30             : 
      31           0 : int lldp_read_chassis_id(tlv_packet *tlv,
      32             :                          uint8_t *type,
      33             :                          uint16_t *length,
      34             :                          uint8_t **data) {
      35             :         uint8_t subtype;
      36             :         int r;
      37             : 
      38           0 :         assert_return(tlv, -EINVAL);
      39             : 
      40           0 :         r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID);
      41           0 :         if (r < 0)
      42           0 :                 goto out2;
      43             : 
      44           0 :         r = tlv_packet_read_u8(tlv, &subtype);
      45           0 :         if (r < 0)
      46           0 :                 goto out1;
      47             : 
      48           0 :         switch (subtype) {
      49             :         case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
      50             : 
      51           0 :                 r = tlv_packet_read_bytes(tlv, data, length);
      52           0 :                 if (r < 0)
      53           0 :                         goto out1;
      54             : 
      55           0 :                 break;
      56             :         default:
      57           0 :                 r = -EOPNOTSUPP;
      58           0 :                 break;
      59             :         }
      60             : 
      61           0 :         *type = subtype;
      62             : 
      63             :  out1:
      64           0 :         (void) lldp_tlv_packet_exit_container(tlv);
      65             : 
      66             :  out2:
      67           0 :         return r;
      68             : }
      69             : 
      70           0 : int lldp_read_port_id(tlv_packet *tlv,
      71             :                       uint8_t *type,
      72             :                       uint16_t *length,
      73             :                       uint8_t **data) {
      74             :         uint8_t subtype;
      75             :         char *s;
      76             :         int r;
      77             : 
      78           0 :         assert_return(tlv, -EINVAL);
      79             : 
      80           0 :         r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID);
      81           0 :         if (r < 0)
      82           0 :                 goto out2;
      83             : 
      84           0 :         r = tlv_packet_read_u8(tlv, &subtype);
      85           0 :         if (r < 0)
      86           0 :                 goto out1;
      87             : 
      88           0 :         switch (subtype) {
      89             :         case LLDP_PORT_SUBTYPE_PORT_COMPONENT:
      90             :         case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
      91             :         case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
      92             :         case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
      93             : 
      94           0 :                 r = tlv_packet_read_string(tlv, &s, length);
      95           0 :                 if (r < 0)
      96           0 :                         goto out1;
      97             : 
      98           0 :                 *data = (uint8_t *) s;
      99             : 
     100           0 :                 break;
     101             :         case LLDP_PORT_SUBTYPE_MAC_ADDRESS:
     102             : 
     103           0 :                 r = tlv_packet_read_bytes(tlv, data, length);
     104           0 :                 if (r < 0)
     105           0 :                         goto out1;
     106             : 
     107           0 :                 break;
     108             :         default:
     109           0 :                 r = -EOPNOTSUPP;
     110           0 :                 break;
     111             :         }
     112             : 
     113           0 :         *type = subtype;
     114             : 
     115             :  out1:
     116           0 :         (void) lldp_tlv_packet_exit_container(tlv);
     117             : 
     118             :  out2:
     119           0 :         return r;
     120             : }
     121             : 
     122           0 : int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl) {
     123             :         int r;
     124             : 
     125           0 :         assert_return(tlv, -EINVAL);
     126             : 
     127           0 :         r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_TTL);
     128           0 :         if (r < 0)
     129           0 :                 goto out;
     130             : 
     131           0 :         r = tlv_packet_read_u16(tlv, ttl);
     132             : 
     133           0 :         (void) lldp_tlv_packet_exit_container(tlv);
     134             : 
     135             :  out:
     136           0 :         return r;
     137             : }
     138             : 
     139           0 : int lldp_read_system_name(tlv_packet *tlv,
     140             :                           uint16_t *length,
     141             :                           char **data) {
     142             :         char *s;
     143             :         int r;
     144             : 
     145           0 :         assert_return(tlv, -EINVAL);
     146             : 
     147           0 :         r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_NAME);
     148           0 :         if (r < 0)
     149           0 :                 return r;
     150             : 
     151           0 :         r = tlv_packet_read_string(tlv, &s, length);
     152           0 :         if (r < 0)
     153           0 :                 goto out;
     154             : 
     155           0 :         *data = (char *) s;
     156             : 
     157             :  out:
     158           0 :         (void) lldp_tlv_packet_exit_container(tlv);
     159             : 
     160           0 :         return r;
     161             : }
     162             : 
     163           0 : int lldp_read_system_description(tlv_packet *tlv,
     164             :                                  uint16_t *length,
     165             :                                  char **data) {
     166             :         char *s;
     167             :         int r;
     168             : 
     169           0 :         assert_return(tlv, -EINVAL);
     170             : 
     171           0 :         r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION);
     172           0 :         if (r < 0)
     173           0 :                 return r;
     174             : 
     175           0 :         r = tlv_packet_read_string(tlv, &s, length);
     176           0 :         if (r < 0)
     177           0 :                 goto out;
     178             : 
     179           0 :         *data = (char *) s;
     180             : 
     181             :  out:
     182           0 :         (void) lldp_tlv_packet_exit_container(tlv);
     183             : 
     184           0 :         return r;
     185             : }
     186             : 
     187           0 : int lldp_read_port_description(tlv_packet *tlv,
     188             :                                uint16_t *length,
     189             :                                char **data) {
     190             :         char *s;
     191             :         int r;
     192             : 
     193           0 :         assert_return(tlv, -EINVAL);
     194             : 
     195           0 :         r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_DESCRIPTION);
     196           0 :         if (r < 0)
     197           0 :                 return r;
     198             : 
     199           0 :         r = tlv_packet_read_string(tlv, &s, length);
     200           0 :         if (r < 0)
     201           0 :                 goto out;
     202             : 
     203           0 :         *data = (char *) s;
     204             : 
     205             :  out:
     206           0 :         (void) lldp_tlv_packet_exit_container(tlv);
     207             : 
     208           0 :         return r;
     209             : }
     210             : 
     211           0 : int lldp_read_system_capability(tlv_packet *tlv, uint16_t *data) {
     212             :         int r;
     213             : 
     214           0 :         assert_return(tlv, -EINVAL);
     215             : 
     216           0 :         r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES);
     217           0 :         if (r < 0)
     218           0 :                 return r;
     219             : 
     220           0 :         r = tlv_packet_read_u16(tlv, data);
     221           0 :         if (r < 0)
     222           0 :                 goto out;
     223             : 
     224           0 :         return 0;
     225             :  out:
     226             : 
     227           0 :         (void) lldp_tlv_packet_exit_container(tlv);
     228             : 
     229           0 :         return r;
     230             : }
     231             : 
     232             : /* 10.5.5.2.2 mibUpdateObjects ()
     233             :  * The mibUpdateObjects () procedure updates the MIB objects corresponding to
     234             :  * the TLVs contained in the received LLDPDU for the LLDP remote system
     235             :  * indicated by the LLDP remote systems update process defined in 10.3.5 */
     236             : 
     237           0 : int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) {
     238             :         lldp_neighbour_port *p;
     239             :         uint16_t length, ttl;
     240             :         uint8_t *data;
     241             :         uint8_t type;
     242             :         int r;
     243             : 
     244           0 :         assert_return(c, -EINVAL);
     245           0 :         assert_return(tlv, -EINVAL);
     246             : 
     247           0 :         r = lldp_read_port_id(tlv, &type, &length, &data);
     248           0 :         if (r < 0)
     249           0 :                 return r;
     250             : 
     251             :         /* Update the packet if we already have */
     252           0 :         LIST_FOREACH(port, p, c->ports) {
     253             : 
     254           0 :                 if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) {
     255             : 
     256           0 :                         r = lldp_read_ttl(tlv, &ttl);
     257           0 :                         if (r < 0)
     258           0 :                                 return r;
     259             : 
     260           0 :                         p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic());
     261             : 
     262           0 :                         tlv_packet_free(p->packet);
     263           0 :                         p->packet = tlv;
     264             : 
     265           0 :                         prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx);
     266             : 
     267           0 :                         return 0;
     268             :                 }
     269             :         }
     270             : 
     271           0 :         return -1;
     272             : }
     273             : 
     274           0 : int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) {
     275             :         lldp_neighbour_port *p, *q;
     276             :         uint8_t *data;
     277             :         uint16_t length;
     278             :         uint8_t type;
     279             :         int r;
     280             : 
     281           0 :         assert_return(c, -EINVAL);
     282           0 :         assert_return(tlv, -EINVAL);
     283             : 
     284           0 :         r = lldp_read_port_id(tlv, &type, &length, &data);
     285           0 :         if (r < 0)
     286           0 :                 return r;
     287             : 
     288           0 :         LIST_FOREACH_SAFE(port, p, q, c->ports) {
     289             : 
     290             :                 /* Find the port */
     291           0 :                 if (p->type == type && p->length == length && !memcmp(p->data, data, p->length)) {
     292           0 :                         lldp_neighbour_port_remove_and_free(p);
     293           0 :                         break;
     294             :                 }
     295             :         }
     296             : 
     297           0 :         return 0;
     298             : }
     299             : 
     300           0 : int lldp_mib_add_objects(Prioq *by_expiry,
     301             :                          Hashmap *neighbour_mib,
     302             :                          tlv_packet *tlv) {
     303           0 :         _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL;
     304           0 :         _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL;
     305             :         lldp_chassis_id chassis_id;
     306           0 :         bool new_chassis = false;
     307             :         uint8_t subtype, *data;
     308             :         uint16_t ttl, length;
     309             :         int r;
     310             : 
     311           0 :         assert_return(by_expiry, -EINVAL);
     312           0 :         assert_return(neighbour_mib, -EINVAL);
     313           0 :         assert_return(tlv, -EINVAL);
     314             : 
     315           0 :         r = lldp_read_chassis_id(tlv, &subtype, &length, &data);
     316           0 :         if (r < 0)
     317           0 :                 goto drop;
     318             : 
     319           0 :         r = lldp_read_ttl(tlv, &ttl);
     320           0 :         if (r < 0)
     321           0 :                 goto drop;
     322             : 
     323             :         /* Make hash key */
     324           0 :         chassis_id.type = subtype;
     325           0 :         chassis_id.length = length;
     326           0 :         chassis_id.data = data;
     327             : 
     328             :         /* Try to find the Chassis */
     329           0 :         c = hashmap_get(neighbour_mib, &chassis_id);
     330           0 :         if (!c) {
     331             : 
     332             :                 /* Don't create chassis if ttl 0 is received . Silently drop it */
     333           0 :                 if (ttl == 0) {
     334           0 :                         log_lldp("TTL value 0 received. Skiping Chassis creation.");
     335           0 :                         goto drop;
     336             :                 }
     337             : 
     338             :                 /* Admission Control: Can we store this packet ? */
     339           0 :                 if (hashmap_size(neighbour_mib) >= LLDP_MIB_MAX_CHASSIS) {
     340             : 
     341           0 :                         log_lldp("Exceeding number of chassie: %d. Dropping ...",
     342             :                                  hashmap_size(neighbour_mib));
     343           0 :                         goto drop;
     344             :                 }
     345             : 
     346           0 :                 r = lldp_chassis_new(tlv, by_expiry, neighbour_mib, &c);
     347           0 :                 if (r < 0)
     348           0 :                         goto drop;
     349             : 
     350           0 :                 new_chassis = true;
     351             : 
     352           0 :                 r = hashmap_put(neighbour_mib, &c->chassis_id, c);
     353           0 :                 if (r < 0)
     354           0 :                         goto drop;
     355             : 
     356             :         } else {
     357             : 
     358             :                 /* When the TTL field is set to zero, the receiving LLDP agent is notified all
     359             :                  * system information associated with the LLDP agent/port is to be deleted */
     360           0 :                 if (ttl == 0) {
     361           0 :                         log_lldp("TTL value 0 received . Deleting associated Port ...");
     362             : 
     363           0 :                         lldp_mib_remove_objects(c, tlv);
     364             : 
     365           0 :                         c = NULL;
     366           0 :                         goto drop;
     367             :                 }
     368             : 
     369             :                 /* if we already have this port just update it */
     370           0 :                 r = lldp_mib_update_objects(c, tlv);
     371           0 :                 if (r >= 0) {
     372           0 :                         c = NULL;
     373           0 :                         return r;
     374             :                 }
     375             : 
     376             :                 /* Admission Control: Can this port attached to the existing chassis ? */
     377           0 :                 if (REFCNT_GET(c->n_ref) >= LLDP_MIB_MAX_PORT_PER_CHASSIS) {
     378           0 :                         log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...",
     379             :                                  REFCNT_GET(c->n_ref));
     380             : 
     381           0 :                         c = NULL;
     382           0 :                         goto drop;
     383             :                 }
     384             :         }
     385             : 
     386             :         /* This is a new port */
     387           0 :         r = lldp_neighbour_port_new(c, tlv, &p);
     388           0 :         if (r < 0)
     389           0 :                 goto drop;
     390             : 
     391           0 :         r = prioq_put(c->by_expiry, p, &p->prioq_idx);
     392           0 :         if (r < 0)
     393           0 :                 goto drop;
     394             : 
     395             :         /* Attach new port to chassis */
     396           0 :         LIST_PREPEND(port, c->ports, p);
     397           0 :         REFCNT_INC(c->n_ref);
     398             : 
     399           0 :         p = NULL;
     400           0 :         c = NULL;
     401             : 
     402           0 :         return 0;
     403             : 
     404             :  drop:
     405           0 :         tlv_packet_free(tlv);
     406             : 
     407           0 :         if (new_chassis)
     408           0 :                 hashmap_remove(neighbour_mib, &c->chassis_id);
     409             : 
     410           0 :         return r;
     411             : }
     412             : 
     413           0 : void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p) {
     414             :         lldp_chassis *c;
     415             : 
     416           0 :         assert(p);
     417           0 :         assert(p->c);
     418             : 
     419           0 :         c = p->c;
     420             : 
     421           0 :         prioq_remove(c->by_expiry, p, &p->prioq_idx);
     422             : 
     423           0 :         LIST_REMOVE(port, c->ports, p);
     424           0 :         lldp_neighbour_port_free(p);
     425             : 
     426             :         /* Drop the Chassis if no port is attached  */
     427           0 :         if (REFCNT_DEC(c->n_ref) <= 1) {
     428           0 :                 hashmap_remove(c->neighbour_mib, &c->chassis_id);
     429           0 :                 lldp_chassis_free(c);
     430             :         }
     431           0 : }
     432             : 
     433           0 : void lldp_neighbour_port_free(lldp_neighbour_port *p) {
     434             : 
     435           0 :         if(!p)
     436           0 :                 return;
     437             : 
     438           0 :         tlv_packet_free(p->packet);
     439             : 
     440           0 :         free(p->data);
     441           0 :         free(p);
     442             : }
     443             : 
     444           0 : int lldp_neighbour_port_new(lldp_chassis *c,
     445             :                             tlv_packet *tlv,
     446             :                             lldp_neighbour_port **ret) {
     447           0 :         _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL;
     448             :         uint16_t length, ttl;
     449             :         uint8_t *data;
     450             :         uint8_t type;
     451             :         int r;
     452             : 
     453           0 :         assert(tlv);
     454             : 
     455           0 :         r = lldp_read_port_id(tlv, &type, &length, &data);
     456           0 :         if (r < 0)
     457           0 :                 return r;
     458             : 
     459           0 :         r = lldp_read_ttl(tlv, &ttl);
     460           0 :         if (r < 0)
     461           0 :                 return r;
     462             : 
     463           0 :         p = new0(lldp_neighbour_port, 1);
     464           0 :         if (!p)
     465           0 :                 return -ENOMEM;
     466             : 
     467           0 :         p->c = c;
     468           0 :         p->type = type;
     469           0 :         p->length = length;
     470           0 :         p->packet = tlv;
     471           0 :         p->prioq_idx = PRIOQ_IDX_NULL;
     472           0 :         p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic());
     473             : 
     474           0 :         p->data = memdup(data, length);
     475           0 :         if (!p->data)
     476           0 :                 return -ENOMEM;
     477             : 
     478           0 :         *ret = p;
     479           0 :         p = NULL;
     480             : 
     481           0 :         return 0;
     482             : }
     483             : 
     484           0 : void lldp_chassis_free(lldp_chassis *c) {
     485             : 
     486           0 :         if (!c)
     487           0 :                 return;
     488             : 
     489           0 :         if (REFCNT_GET(c->n_ref) > 1)
     490           0 :                 return;
     491             : 
     492           0 :         free(c->chassis_id.data);
     493           0 :         free(c);
     494             : }
     495             : 
     496           0 : int lldp_chassis_new(tlv_packet *tlv,
     497             :                      Prioq *by_expiry,
     498             :                      Hashmap *neighbour_mib,
     499             :                      lldp_chassis **ret) {
     500           0 :         _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL;
     501             :         uint16_t length;
     502             :         uint8_t *data;
     503             :         uint8_t type;
     504             :         int r;
     505             : 
     506           0 :         assert(tlv);
     507             : 
     508           0 :         r = lldp_read_chassis_id(tlv, &type, &length, &data);
     509           0 :         if (r < 0)
     510           0 :                 return r;
     511             : 
     512           0 :         c = new0(lldp_chassis, 1);
     513           0 :         if (!c)
     514           0 :                 return -ENOMEM;
     515             : 
     516           0 :         c->n_ref = REFCNT_INIT;
     517           0 :         c->chassis_id.type = type;
     518           0 :         c->chassis_id.length = length;
     519             : 
     520           0 :         c->chassis_id.data = memdup(data, length);
     521           0 :         if (!c->chassis_id.data)
     522           0 :                 return -ENOMEM;
     523             : 
     524           0 :         LIST_HEAD_INIT(c->ports);
     525             : 
     526           0 :         c->by_expiry = by_expiry;
     527           0 :         c->neighbour_mib = neighbour_mib;
     528             : 
     529           0 :         *ret = c;
     530           0 :         c = NULL;
     531             : 
     532           0 :         return 0;
     533             : }

Generated by: LCOV version 1.11