From 2212d76d08f3bc34c683aed1a6736325b841625c Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sun, 21 Jun 2015 20:27:04 +0200 Subject: [PATCH] lldp: add reference counter to struct tlv_packet Add a reference counter to the tlv_packet structure so that it can be shared between multiple users and properly free'd when no longer in use. --- src/libsystemd-network/lldp-internal.c | 6 +++--- src/libsystemd-network/lldp-tlv.c | 23 +++++++++++++++++++++-- src/libsystemd-network/lldp-tlv.h | 9 ++++++--- src/libsystemd-network/sd-lldp.c | 2 +- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c index 3c04898..2906b5a 100644 --- a/src/libsystemd-network/lldp-internal.c +++ b/src/libsystemd-network/lldp-internal.c @@ -259,7 +259,7 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) { p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - tlv_packet_free(p->packet); + tlv_packet_unref(p->packet); p->packet = tlv; prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx); @@ -401,7 +401,7 @@ int lldp_mib_add_objects(Prioq *by_expiry, return 0; drop: - tlv_packet_free(tlv); + tlv_packet_unref(tlv); if (new_chassis) hashmap_remove(neighbour_mib, &c->chassis_id); @@ -435,7 +435,7 @@ void lldp_neighbour_port_free(lldp_neighbour_port *p) { if(!p) return; - tlv_packet_free(p->packet); + tlv_packet_unref(p->packet); free(p->data); free(p); diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c index 0cea5b1..1370d21 100644 --- a/src/libsystemd-network/lldp-tlv.c +++ b/src/libsystemd-network/lldp-tlv.c @@ -54,22 +54,41 @@ int tlv_packet_new(tlv_packet **ret) { return -ENOMEM; LIST_HEAD_INIT(m->sections); + m->n_ref = 1; *ret = m; return 0; } -void tlv_packet_free(tlv_packet *m) { +tlv_packet *tlv_packet_ref(tlv_packet *m) { + + if (!m) + return NULL; + + assert(m->n_ref > 0); + m->n_ref++; + + return m; +} + +tlv_packet *tlv_packet_unref(tlv_packet *m) { tlv_section *s, *n; if (!m) - return; + return NULL; + + assert(m->n_ref > 0); + m->n_ref--; + + if (m->n_ref > 0) + return m; LIST_FOREACH_SAFE(section, s, n, m->sections) tlv_section_free(s); free(m); + return NULL; } int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) { diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h index ce3334e..f682997 100644 --- a/src/libsystemd-network/lldp-tlv.h +++ b/src/libsystemd-network/lldp-tlv.h @@ -45,6 +45,8 @@ int tlv_section_new(tlv_section **ret); void tlv_section_free(tlv_section *ret); struct tlv_packet { + unsigned n_ref; + uint16_t type; uint16_t length; usec_t ts; @@ -61,10 +63,11 @@ struct tlv_packet { }; int tlv_packet_new(tlv_packet **ret); -void tlv_packet_free(tlv_packet *m); +tlv_packet *tlv_packet_ref(tlv_packet *m); +tlv_packet *tlv_packet_unref(tlv_packet *m); -DEFINE_TRIVIAL_CLEANUP_FUNC(tlv_packet*, tlv_packet_free); -#define _cleanup_tlv_packet_free_ _cleanup_(tlv_packet_freep) +DEFINE_TRIVIAL_CLEANUP_FUNC(tlv_packet*, tlv_packet_unref); +#define _cleanup_tlv_packet_free_ _cleanup_(tlv_packet_unrefp) int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type); int lldp_tlv_packet_close_container(tlv_packet *m); diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 1751288..53cd19a 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -338,7 +338,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { lldp->statistics.stats_frames_in_errors_total ++; } - tlv_packet_free(tlv); + tlv_packet_unref(tlv); return 0; } -- 2.7.4