diff --git a/port.c b/port.c index f26f1db..27d9885 100644 --- a/port.c +++ b/port.c @@ -2311,6 +2311,7 @@ void port_close(struct port *p) rtnl_close(p->fda.fd[FD_RTNL]); } + unicast_client_cleanup(p); unicast_service_cleanup(p); transport_destroy(p->trp); tsproc_destroy(p->tsproc); @@ -3039,25 +3040,25 @@ struct port *port_open(const char *phc_device, p->delayMechanism = config_get_int(cfg, p->name, "delay_mechanism"); p->versionNumber = PTP_VERSION; - if (number && unicast_client_claim_table(p)) { + if (number && unicast_client_initialize(p)) { goto err_transport; } if (unicast_client_enabled(p) && config_set_section_int(cfg, p->name, "hybrid_e2e", 1)) { - goto err_transport; + goto err_uc_client; } if (number && unicast_service_initialize(p)) { - goto err_transport; + goto err_uc_client; } p->hybrid_e2e = config_get_int(cfg, p->name, "hybrid_e2e"); if (number && type == CLOCK_TYPE_P2P && p->delayMechanism != DM_P2P) { pr_err("port %d: P2P TC needs P2P ports", number); - goto err_transport; + goto err_uc_service; } if (number && type == CLOCK_TYPE_E2E && p->delayMechanism != DM_E2E) { pr_err("port %d: E2E TC needs E2E ports", number); - goto err_transport; + goto err_uc_service; } if (p->hybrid_e2e && p->delayMechanism != DM_E2E) { pr_warning("port %d: hybrid_e2e only works with E2E", number); @@ -3083,7 +3084,7 @@ struct port *port_open(const char *phc_device, config_get_int(cfg, p->name, "delay_filter_length")); if (!p->tsproc) { pr_err("Failed to create time stamp processor"); - goto err_transport; + goto err_uc_service; } p->nrate.ratio = 1.0; @@ -3100,6 +3101,10 @@ struct port *port_open(const char *phc_device, err_tsproc: tsproc_destroy(p->tsproc); +err_uc_service: + unicast_service_cleanup(p); +err_uc_client: + unicast_client_cleanup(p); err_transport: transport_destroy(p->trp); err_port: diff --git a/ptp4l.8 b/ptp4l.8 index ab156d9..c4e1464 100644 --- a/ptp4l.8 +++ b/ptp4l.8 @@ -275,9 +275,7 @@ The default is 0 (disabled). When set to a positive integer, this option specifies the table id to be used for unicast discovery. Each table lives in its own section and has a unique, positive numerical ID. Entries in the table are a -pair of transport type and protocol address. Tables may not be shared -between ports, but nothing prevents table entries from appearing in -more than table. +pair of transport type and protocol address. The default is 0 (unicast discovery disabled). .TP .B unicast_req_duration diff --git a/unicast_client.c b/unicast_client.c index 6495d6f..67e50ce 100644 --- a/unicast_client.c +++ b/unicast_client.c @@ -17,6 +17,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA. */ +#include + #include "port.h" #include "port_private.h" #include "print.h" @@ -250,6 +252,45 @@ out: return err; } +static void free_master_table(struct unicast_master_table *table) +{ + struct unicast_master_address *address; + + while ((address = STAILQ_FIRST(&table->addrs))) { + STAILQ_REMOVE_HEAD(&table->addrs, list); + free(address); + } + free(table->peer_name); + free(table); +} + +static struct unicast_master_table * +clone_master_table(struct unicast_master_table *table) +{ + struct unicast_master_address *address, *cloned_address; + struct unicast_master_table *cloned_table; + + cloned_table = malloc(sizeof(*cloned_table)); + if (!cloned_table) + return NULL; + *cloned_table = *table; + STAILQ_INIT(&cloned_table->addrs); + memset(&cloned_table->list, 0, sizeof(cloned_table->list)); + if (table->peer_name) + cloned_table->peer_name = strdup(table->peer_name); + + STAILQ_FOREACH(address, &table->addrs, list) { + cloned_address = malloc(sizeof(*cloned_address)); + if (!cloned_address) { + free_master_table(cloned_table); + return NULL; + } + *cloned_address = *address; + STAILQ_INSERT_TAIL(&cloned_table->addrs, cloned_address, list); + } + return cloned_table; +} + /* public methods */ int unicast_client_cancel(struct port *p, struct ptp_message *m, @@ -302,7 +343,7 @@ out: return err; } -int unicast_client_claim_table(struct port *p) +int unicast_client_initialize(struct port *p) { struct unicast_master_address *master, *peer; struct config *cfg = clock_config(p->clock); @@ -322,9 +363,9 @@ int unicast_client_claim_table(struct port *p) pr_err("port %d: no table with id %d", portnum(p), table_id); return -1; } - if (table->port) { - pr_err("port %d: table %d already claimed by port %d", - portnum(p), table_id, table->port); + table = clone_master_table(table); + if (!table) { + pr_err("low memory"); return -1; } peer = &table->peer_addr; @@ -332,6 +373,7 @@ int unicast_client_claim_table(struct port *p) table->peer_name, &peer->address)) { pr_err("port %d: bad peer address: %s", portnum(p), table->peer_name); + free_master_table(table); return -1; } STAILQ_FOREACH(master, &table->addrs, list) { @@ -352,6 +394,12 @@ int unicast_client_claim_table(struct port *p) return 0; } +void unicast_client_cleanup(struct port *p) +{ + if (p->unicast_master_table) + free_master_table(p->unicast_master_table); +} + int unicast_client_enabled(struct port *p) { return p->unicast_master_table ? 1 : 0; diff --git a/unicast_client.h b/unicast_client.h index fc8dc6f..16e291f 100644 --- a/unicast_client.h +++ b/unicast_client.h @@ -37,7 +37,13 @@ int unicast_client_cancel(struct port *p, struct ptp_message *m, * @param port The port in question. * @return Zero on success, non-zero otherwise. */ -int unicast_client_claim_table(struct port *port); +int unicast_client_initialize(struct port *port); + +/** + * Frees all of the resources associated with a port's unicast client. + * @param p The port in question. + */ +void unicast_client_cleanup(struct port *p); /** * Tests whether a unicast master table is associated with a given port.