1098 lines
35 KiB
Diff
1098 lines
35 KiB
Diff
commit e6baa96f0bf07e0d86ace943472ffacfb3b32551
|
|
Author: Miroslav Lichvar (via linuxptp-devel Mailing List) <linuxptp-devel@lists.nwtime.org>
|
|
Date: Thu Jul 31 11:35:44 2025 +0200
|
|
|
|
util: Add functions for dropping root privileges.
|
|
|
|
Add a function to switch the process UID/GID to a specified user in
|
|
order to drop the root privileges. Keep only the capabilities needed to
|
|
adjust the clock, enable HW timestamping, bind to privileged ports and
|
|
raw sockets, using the libcap library. Initialize the supplementary
|
|
groups of the user to make it easier to give it permissions to open PHC
|
|
devices by adding it to a system group.
|
|
|
|
Add a function to create a directory for a UDS address with a specified
|
|
owner, where the programs will be able to bind and unlink their sockets
|
|
without root privileges.
|
|
|
|
(Rebased to 4.4)
|
|
|
|
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
|
|
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
|
|
diff --git a/incdefs.sh b/incdefs.sh
|
|
index 060cc0b..4af992d 100755
|
|
--- a/incdefs.sh
|
|
+++ b/incdefs.sh
|
|
@@ -140,6 +140,14 @@ user_flags()
|
|
fi
|
|
done
|
|
done
|
|
+
|
|
+ # Look for libcap support.
|
|
+ for d in $dirs; do
|
|
+ if test -e $d/sys/capability.h; then
|
|
+ printf " -DHAVE_LIBCAP"
|
|
+ break
|
|
+ fi
|
|
+ done
|
|
}
|
|
|
|
#
|
|
diff --git a/makefile b/makefile
|
|
index 3c2406b..2069e7e 100644
|
|
--- a/makefile
|
|
+++ b/makefile
|
|
@@ -62,6 +62,10 @@ LDLIBS += -lcrypto
|
|
SECURITY += sad_openssl.o
|
|
endif
|
|
|
|
+ifneq (,$(findstring -DHAVE_LIBCAP,$(incdefs)))
|
|
+LDLIBS += -lcap
|
|
+endif
|
|
+
|
|
prefix = /usr/local
|
|
sbindir = $(prefix)/sbin
|
|
mandir = $(prefix)/man
|
|
diff --git a/util.c b/util.c
|
|
index 5b0302b..c211158 100644
|
|
--- a/util.c
|
|
+++ b/util.c
|
|
@@ -19,13 +19,25 @@
|
|
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
#include <linux/limits.h>
|
|
+#include <libgen.h>
|
|
#include <signal.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/types.h>
|
|
+
|
|
+#ifdef HAVE_LIBCAP
|
|
+#include <grp.h>
|
|
+#include <pwd.h>
|
|
+#include <sys/prctl.h>
|
|
+#include <sys/capability.h>
|
|
+#include <unistd.h>
|
|
+#endif
|
|
|
|
#include "address.h"
|
|
+#include "interface.h"
|
|
#include "phc.h"
|
|
#include "print.h"
|
|
#include "sk.h"
|
|
@@ -894,3 +906,102 @@ bool base64_decode(const char *in_str, size_t in_len, void *out, size_t *out_len
|
|
*out_len = *out_len - len;
|
|
return true;
|
|
}
|
|
+
|
|
+void create_uds_directory(const char *address, const char *user)
|
|
+{
|
|
+ char path[MAX_IFNAME_SIZE + 1], *dir;
|
|
+#ifdef HAVE_LIBCAP
|
|
+ struct passwd *pw;
|
|
+#endif
|
|
+
|
|
+ if (snprintf(path, sizeof(path), "%s", address) >= sizeof(path)) {
|
|
+ pr_err("path too long for UDS");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ dir = dirname(path);
|
|
+
|
|
+ /* Don't do anything if it already exists or cannot be created */
|
|
+ if (mkdir(dir, 0775)) {
|
|
+ if (errno != EEXIST)
|
|
+ pr_err("failed to create %s: %m", dir);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+#ifdef HAVE_LIBCAP
|
|
+ if (user[0] == '\0')
|
|
+ return;
|
|
+
|
|
+ pw = getpwnam(user);
|
|
+ if (!pw) {
|
|
+ pr_err("failed to get user/group ID of %s", user);
|
|
+ rmdir(dir);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (lchown(dir, pw->pw_uid, pw->pw_gid)) {
|
|
+ pr_err("failed to change owner of %s: %m", dir);
|
|
+ rmdir(dir);
|
|
+ return;
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+int drop_root_privileges(const char *user)
|
|
+{
|
|
+#ifdef HAVE_LIBCAP
|
|
+ struct passwd *pw;
|
|
+ cap_t cap;
|
|
+#endif
|
|
+
|
|
+ if (user[0] == '\0')
|
|
+ return 0;
|
|
+
|
|
+#ifdef HAVE_LIBCAP
|
|
+ pw = getpwnam(user);
|
|
+ if (!pw) {
|
|
+ pr_err("failed to get user/group ID of %s", user);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (prctl(PR_SET_KEEPCAPS, 1)) {
|
|
+ pr_err("failed to set KEEPCAPS flag");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (initgroups(user, pw->pw_gid)) {
|
|
+ pr_err("failed to init supplementary groups");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (setgid(pw->pw_gid)) {
|
|
+ pr_err("failed to set group ID");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (setuid(pw->pw_uid)) {
|
|
+ pr_err("failed to set user ID");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ cap = cap_from_text("cap_sys_time,cap_net_admin,"
|
|
+ "cap_net_bind_service,cap_net_raw=ep");
|
|
+ if (!cap) {
|
|
+ pr_err("failed to initialize capabilities");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (cap_set_proc(cap)) {
|
|
+ pr_err("failed to set process capabilities");
|
|
+ cap_free(cap);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ cap_free(cap);
|
|
+
|
|
+ return 0;
|
|
+#else
|
|
+ pr_err("cannot drop root privileges without libcap");
|
|
+ return -1;
|
|
+#endif
|
|
+}
|
|
diff --git a/util.h b/util.h
|
|
index b228745..ed48b21 100644
|
|
--- a/util.h
|
|
+++ b/util.h
|
|
@@ -502,4 +502,24 @@ size_t base64_len(const char *str, size_t len);
|
|
*/
|
|
bool base64_decode(const char *in_str, size_t in_len, void *out, size_t *out_len);
|
|
|
|
+/*
|
|
+ * Create directory for a UDS address owned by the specified user.
|
|
+ * Don't do anything if it already exists, even if it has a different owner.
|
|
+ *
|
|
+ * @param address UDS address.
|
|
+ * @param user Name of the user.
|
|
+ */
|
|
+void create_uds_directory(const char *address, const char *user);
|
|
+
|
|
+/**
|
|
+ * Change the user/group ID in order to drop the root privileges. Initialize
|
|
+ * supplementary groups of the user. Keep only capabilities needed to set
|
|
+ * and adjust clocks, bind to a privileged port, enable and configure HW
|
|
+ * timestamping, and open a raw socket.
|
|
+ *
|
|
+ * @param user Name of the user.
|
|
+ * @return 0 on success, -1 on error.
|
|
+ */
|
|
+int drop_root_privileges(const char *user);
|
|
+
|
|
#endif
|
|
|
|
commit ee15ee7cfadd013cd7ccc160d6d505d674275740
|
|
Author: Miroslav Lichvar (via linuxptp-devel Mailing List) <linuxptp-devel@lists.nwtime.org>
|
|
Date: Thu Jul 31 11:35:45 2025 +0200
|
|
|
|
clock: Add support for dropping root privileges.
|
|
|
|
Add "user" option to specify the user to which ptp4l should switch after
|
|
opening the PHC device and before binding the network/UDS ports. Create
|
|
the directory that will contain the UDS-RW/RO sockets if it does not
|
|
exist and change its ownership to allow the UDS sockets to be bound and
|
|
unlinked there.
|
|
|
|
The default is to keep the identity of the user which started ptp4l.
|
|
|
|
In the jbod mode, or with a bond interface, the PHC devices need to
|
|
have the permissions set for the non-root user to be able to open them
|
|
(e.g. by adding the user to a system group owning the PHC devices).
|
|
|
|
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
|
|
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
|
|
diff --git a/clock.c b/clock.c
|
|
index 7c30066..7ffdbaa 100644
|
|
--- a/clock.c
|
|
+++ b/clock.c
|
|
@@ -1109,7 +1109,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
|
|
{
|
|
int conf_phc_index, i, max_adj = 0, phc_index, required_modes = 0, sfl, sw_ts;
|
|
enum servo_type servo = config_get_int(config, NULL, "clock_servo");
|
|
- char ts_label[IF_NAMESIZE], phc[32], *tmp;
|
|
+ char ts_label[IF_NAMESIZE], phc[32], *tmp, *user;
|
|
enum timestamp_type timestamping;
|
|
struct clock *c = &the_clock;
|
|
const char *uds_ifname;
|
|
@@ -1429,6 +1429,12 @@ struct clock *clock_create(enum clock_type type, struct config *config,
|
|
return NULL;
|
|
}
|
|
|
|
+ user = config_get_string(config, NULL, "user");
|
|
+ create_uds_directory(config_get_string(config, NULL, "uds_address"),
|
|
+ user);
|
|
+ create_uds_directory(config_get_string(config, NULL, "uds_ro_address"),
|
|
+ user);
|
|
+
|
|
/* Create the UDS interfaces. */
|
|
|
|
c->uds_rw_port = port_open(phc_device, phc_index, timestamping, 0,
|
|
@@ -1459,6 +1465,18 @@ struct clock *clock_create(enum clock_type type, struct config *config,
|
|
}
|
|
}
|
|
|
|
+ /*
|
|
+ * Drop the root privileges if configured to do so. It needs to be done
|
|
+ * after opening the ports as generic netlink sockets (whose binding
|
|
+ * requires CAP_SYS_ADMIN) are used to detect virtual clocks. The port
|
|
+ * sockets will be bound and HW timestamping configured later when
|
|
+ * handling the port INITIALIZING state. The process keeps
|
|
+ * CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, and CAP_NET_RAW to be able to
|
|
+ * do that.
|
|
+ */
|
|
+ if (drop_root_privileges(user))
|
|
+ return NULL;
|
|
+
|
|
c->dds.numberPorts = c->nports;
|
|
|
|
LIST_FOREACH(p, &c->ports, list) {
|
|
diff --git a/config.c b/config.c
|
|
index 6c602ef..3c5d143 100644
|
|
--- a/config.c
|
|
+++ b/config.c
|
|
@@ -395,6 +395,7 @@ struct config_item config_tab[] = {
|
|
PORT_ITEM_INT("unicast_master_table", 0, 0, INT_MAX),
|
|
PORT_ITEM_INT("unicast_req_duration", 3600, 10, INT_MAX),
|
|
GLOB_ITEM_INT("use_syslog", 1, 0, 1),
|
|
+ GLOB_ITEM_STR("user", ""),
|
|
GLOB_ITEM_STR("userDescription", ""),
|
|
GLOB_ITEM_INT("utc_offset", CURRENT_UTC_OFFSET, 0, INT_MAX),
|
|
GLOB_ITEM_INT("verbose", 0, 0, 1),
|
|
diff --git a/ptp4l.8 b/ptp4l.8
|
|
index 87900e3..a302997 100644
|
|
--- a/ptp4l.8
|
|
+++ b/ptp4l.8
|
|
@@ -1040,7 +1040,10 @@ is only relevant with IPv6 transport. See RFC 4291. The default is
|
|
.TP
|
|
.B uds_address
|
|
Specifies the address of the UNIX domain socket for receiving local
|
|
-management messages. The default is /var/run/ptp4l.
|
|
+management messages. The directory containing the socket will be created on
|
|
+start if it does not exist, with owner set to the user specified by the
|
|
+.B user
|
|
+option. The default is /var/run/ptp4l.
|
|
|
|
.TP
|
|
.B uds_file_mode
|
|
@@ -1088,6 +1091,19 @@ This option enables using the "write phase" feature of a PTP Hardware
|
|
Clock. If supported by the device, this mode uses the hardware's
|
|
built in phase offset control instead of frequency offset control.
|
|
The default value is 0 (disabled).
|
|
+.TP
|
|
+.B user
|
|
+The name of the user to which should
|
|
+.B ptp4l
|
|
+switch after start in order to drop the root privileges. By default,
|
|
+.B ptp4l
|
|
+will keep the identity of the user under which it is started. With the
|
|
+.B boundary_clock_jbod
|
|
+option, or if using a bonded interface, the non-root user must have permissions
|
|
+to open the PHC devices to be able to switch between them. If using the ntpshm
|
|
+or refclock_sock servo, the user must have also permissions to attach to the
|
|
+shared memory segment if it already exists or connect to the refclock socket
|
|
+respectively.
|
|
|
|
.SH UNICAST DISCOVERY OPTIONS
|
|
|
|
|
|
commit 91fb662377222a4ef58fce550a8488ef2768d57e
|
|
Author: Miroslav Lichvar (via linuxptp-devel Mailing List) <linuxptp-devel@lists.nwtime.org>
|
|
Date: Thu Jul 31 11:35:46 2025 +0200
|
|
|
|
uds: Copy ownership of server socket in pmc clients.
|
|
|
|
ptp4l sending a response to a pmc client needs to have permissions to
|
|
write to the client's UNIX domain socket. If ptp4l runs under a non-root
|
|
user, it cannot write to sockets bound by the pmc client if it did that
|
|
as root.
|
|
|
|
After binding the client socket, change its owner to the owner of the
|
|
server socket, so it can send the client a response.
|
|
|
|
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
|
|
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
|
|
diff --git a/uds.c b/uds.c
|
|
index 4ddee7b..ce7e92d 100644
|
|
--- a/uds.c
|
|
+++ b/uds.c
|
|
@@ -60,6 +60,7 @@ static int uds_open(struct transport *t, struct interface *iface, struct fdarray
|
|
const char* file_mode_cfg;
|
|
struct sockaddr_un sa;
|
|
mode_t file_mode;
|
|
+ struct stat st;
|
|
int fd, err;
|
|
|
|
fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
|
@@ -97,6 +98,20 @@ static int uds_open(struct transport *t, struct interface *iface, struct fdarray
|
|
uds->address.len = sizeof(sa);
|
|
|
|
chmod(name, file_mode);
|
|
+
|
|
+ /*
|
|
+ * In the client, copy the ownership of the server's socket if it runs
|
|
+ * under a non-root user to allow it to send a response to the client
|
|
+ * running under root. Avoid following a symlink if the socket is
|
|
+ * replaced (e.g. by compromised ptp4l process).
|
|
+ */
|
|
+ if (uds_path[0] != '\0') {
|
|
+ if (!lstat(uds_path, &st) && (st.st_uid || st.st_gid) &&
|
|
+ lchown(name, st.st_uid, st.st_gid)) {
|
|
+ pr_err("uds: failed to change socket ownership: %m");
|
|
+ }
|
|
+ }
|
|
+
|
|
fda->fd[FD_EVENT] = -1;
|
|
fda->fd[FD_GENERAL] = fd;
|
|
return 0;
|
|
|
|
commit eb95a385c9e5653b55b25166f65ca0d8139a2c6e
|
|
Author: Miroslav Lichvar (via linuxptp-devel Mailing List) <linuxptp-devel@lists.nwtime.org>
|
|
Date: Thu Jul 31 11:35:47 2025 +0200
|
|
|
|
uds: Don't call chmod() on client socket.
|
|
|
|
The pmc clients should not need to modify the permissions of their
|
|
socket (following the uds_file_mode setting), they can rely on their
|
|
umask.
|
|
|
|
Make the chmod() call on the bound socket only in the server.
|
|
|
|
This removes a race condition between the bind() and chmod() calls that
|
|
could potentially be exploited by ptp4l running under a non-root user.
|
|
It could replace the socket with a symlink in order to make the client
|
|
running under root to change the mode of a different file.
|
|
|
|
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
|
|
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
|
|
diff --git a/uds.c b/uds.c
|
|
index ce7e92d..d74b7a8 100644
|
|
--- a/uds.c
|
|
+++ b/uds.c
|
|
@@ -97,19 +97,20 @@ static int uds_open(struct transport *t, struct interface *iface, struct fdarray
|
|
uds->address.sun = sa;
|
|
uds->address.len = sizeof(sa);
|
|
|
|
- chmod(name, file_mode);
|
|
-
|
|
/*
|
|
* In the client, copy the ownership of the server's socket if it runs
|
|
* under a non-root user to allow it to send a response to the client
|
|
* running under root. Avoid following a symlink if the socket is
|
|
- * replaced (e.g. by compromised ptp4l process).
|
|
+ * replaced (e.g. by compromised ptp4l process). The server just sets
|
|
+ * the permissions on its socket per configuration.
|
|
*/
|
|
if (uds_path[0] != '\0') {
|
|
if (!lstat(uds_path, &st) && (st.st_uid || st.st_gid) &&
|
|
lchown(name, st.st_uid, st.st_gid)) {
|
|
pr_err("uds: failed to change socket ownership: %m");
|
|
}
|
|
+ } else {
|
|
+ chmod(name, file_mode);
|
|
}
|
|
|
|
fda->fd[FD_EVENT] = -1;
|
|
|
|
commit 48367c57de49671ae36c1df7d4d2c344ac164ef6
|
|
Author: Miroslav Lichvar (via linuxptp-devel Mailing List) <linuxptp-devel@lists.nwtime.org>
|
|
Date: Thu Jul 31 11:35:48 2025 +0200
|
|
|
|
Follow server UDS location in pmc clients.
|
|
|
|
Modify pmc, phc2sys, ts2phc, and tz2alt to bind their client sockets in
|
|
the same directory as the server's socket instead of hardcoded /var/run.
|
|
In the pmc program it's the default, it can still be configured with the
|
|
-i option to any address.
|
|
|
|
This allows the clients to be started under the same user as to which
|
|
ptp4l is configured to switch, with all their sockets in the same
|
|
directory where the user has write permissions. phc2sys and ts2phc will
|
|
need also permissions to open the PHC devices and the CAP_SYS_TIME
|
|
capability needed to adjust the clock (e.g. set by setpriv(1)).
|
|
|
|
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
|
|
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
|
|
diff --git a/phc2sys.c b/phc2sys.c
|
|
index ddd0a6a..dd72c17 100644
|
|
--- a/phc2sys.c
|
|
+++ b/phc2sys.c
|
|
@@ -1512,7 +1512,7 @@ int main(int argc, char *argv[])
|
|
}
|
|
|
|
snprintf(uds_local, sizeof(uds_local),
|
|
- "/var/run/phc2sys.%d.%d", getpid(), i);
|
|
+ "phc2sys.%d.%d", getpid(), i);
|
|
|
|
if (uds_remote_cnt > i)
|
|
config_set_string(cfg, "uds_address",
|
|
@@ -1554,8 +1554,7 @@ int main(int argc, char *argv[])
|
|
r = -1;
|
|
|
|
if (wait_sync || !domains[0].forced_sync_offset) {
|
|
- snprintf(uds_local, sizeof(uds_local),
|
|
- "/var/run/phc2sys.%d", getpid());
|
|
+ snprintf(uds_local, sizeof(uds_local), "phc2sys.%d", getpid());
|
|
|
|
if (uds_remote_cnt > 0)
|
|
config_set_string(cfg, "uds_address",
|
|
diff --git a/pmc.8 b/pmc.8
|
|
index 2b08f4d..1019d59 100644
|
|
--- a/pmc.8
|
|
+++ b/pmc.8
|
|
@@ -81,8 +81,9 @@ Specify the boundary hops value in sent messages. The default is 1.
|
|
Specify the domain number in sent messages. The default is 0.
|
|
.TP
|
|
.BI \-i " interface"
|
|
-Specify the network interface. The default is /var/run/pmc.$pid for the Unix Domain
|
|
-Socket transport and eth0 for the other transports.
|
|
+Specify the network interface. The default is pmc.$pid for the Unix Domain
|
|
+Socket transport and eth0 for the other transports. A relative path of the Unix
|
|
+Domain socket is relative to the directory of the server's socket.
|
|
.TP
|
|
.BI \-s " uds-address"
|
|
Specifies the address of the server's UNIX domain socket.
|
|
diff --git a/pmc.c b/pmc.c
|
|
index 6a6a94e..c75879f 100644
|
|
--- a/pmc.c
|
|
+++ b/pmc.c
|
|
@@ -705,7 +705,7 @@ static void usage(char *progname)
|
|
" -f [file] read configuration from 'file'\n"
|
|
" -h prints this message and exits\n"
|
|
" -i [dev] interface device to use, default 'eth0'\n"
|
|
- " for network and '/var/run/pmc.$pid' for UDS.\n"
|
|
+ " for network and 'pmc.$pid' for UDS.\n"
|
|
" -s [path] server address for UDS, default '/var/run/ptp4l'.\n"
|
|
" -t [hex] transport specific field, default 0x0\n"
|
|
" -v prints the software version and exits\n"
|
|
@@ -845,7 +845,7 @@ int main(int argc, char *argv[])
|
|
if (!iface_name) {
|
|
if (transport_type == TRANS_UDS) {
|
|
snprintf(uds_local, sizeof(uds_local),
|
|
- "/var/run/pmc.%d", getpid());
|
|
+ "pmc.%d", getpid());
|
|
iface_name = uds_local;
|
|
} else {
|
|
iface_name = "eth0";
|
|
diff --git a/pmc_common.c b/pmc_common.c
|
|
index b55e7ec..a67b01f 100644
|
|
--- a/pmc_common.c
|
|
+++ b/pmc_common.c
|
|
@@ -18,6 +18,7 @@
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
#include <errno.h>
|
|
+#include <libgen.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
@@ -515,12 +516,38 @@ struct pmc {
|
|
UInteger8 allow_unauth;
|
|
};
|
|
|
|
+static int complete_uds_address(struct config *cfg, const char *iface,
|
|
+ char *uds, size_t len)
|
|
+{
|
|
+ char buf[MAX_IFNAME_SIZE + 1];
|
|
+
|
|
+ /* Don't change absolute paths */
|
|
+ if (iface[0] == '/') {
|
|
+ if (snprintf(uds, len, "%s", iface) >= len) {
|
|
+ pr_err("UDS path too long");
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Relative paths are relative to the directory of the server socket */
|
|
+ if (snprintf(buf, sizeof(buf), "%s", config_get_string(cfg, NULL,
|
|
+ "uds_address")) >= sizeof(buf) ||
|
|
+ snprintf(uds, len, "%s/%s", dirname(buf), iface) >= len) {
|
|
+ pr_err("UDS path too long");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type,
|
|
const char *iface_name, const char *remote_address,
|
|
UInteger8 boundary_hops, UInteger8 domain_number,
|
|
UInteger8 transport_specific, UInteger8 allow_unauth,
|
|
int zero_datalen)
|
|
{
|
|
+ char uds[MAX_IFNAME_SIZE + 1];
|
|
struct pmc *pmc;
|
|
UInteger32 proc_id;
|
|
|
|
@@ -533,6 +560,9 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type,
|
|
pmc->port_identity.clockIdentity.id[6] = (proc_id & 0xFF000000) >> 24;
|
|
pmc->port_identity.clockIdentity.id[7] = (proc_id & 0x00FF0000) >> 16;
|
|
pmc->port_identity.portNumber = proc_id & 0xFFFF;
|
|
+ if (complete_uds_address(cfg, iface_name, uds, sizeof(uds)))
|
|
+ goto failed;
|
|
+ iface_name = uds;
|
|
} else {
|
|
if (generate_clock_identity(&pmc->port_identity.clockIdentity,
|
|
iface_name)) {
|
|
diff --git a/ts2phc.c b/ts2phc.c
|
|
index 5448496..2d699c6 100644
|
|
--- a/ts2phc.c
|
|
+++ b/ts2phc.c
|
|
@@ -715,8 +715,7 @@ int main(int argc, char *argv[])
|
|
return -1;
|
|
}
|
|
|
|
- snprintf(uds_local, sizeof(uds_local), "/var/run/ts2phc.%d",
|
|
- getpid());
|
|
+ snprintf(uds_local, sizeof(uds_local), "ts2phc.%d", getpid());
|
|
|
|
if (autocfg) {
|
|
err = init_pmc_node(cfg, priv.agent, uds_local,
|
|
diff --git a/tz2alt.c b/tz2alt.c
|
|
index 905aa0b..afd1941 100644
|
|
--- a/tz2alt.c
|
|
+++ b/tz2alt.c
|
|
@@ -384,7 +384,7 @@ int main(int argc, char *argv[])
|
|
print_set_progname(progname);
|
|
print_set_tag(config_get_string(cfg, NULL, "message_tag"));
|
|
print_set_level(config_get_int(cfg, NULL, "logging_level"));
|
|
- snprintf(uds_local, sizeof(uds_local), "/var/run/tztool.%d", getpid());
|
|
+ snprintf(uds_local, sizeof(uds_local), "tztool.%d", getpid());
|
|
|
|
err = do_tztool(timezone);
|
|
out:
|
|
|
|
commit 009a794e098e0de4db03d3bae33216a9aecce6bb
|
|
Author: Miroslav Lichvar (via linuxptp-devel Mailing List) <linuxptp-devel@lists.nwtime.org>
|
|
Date: Thu Jul 31 11:35:49 2025 +0200
|
|
|
|
config: Move default UDS addresses to /var/run/ptp.
|
|
|
|
/var/run is normally not writable for non-root users. Move the default
|
|
server UDS and CMLDS addresses to /var/run/ptp, which will be created by
|
|
ptp4l the first time it runs if it does not exist. This makes the
|
|
default work well in both cases when the linuxptp programs are running
|
|
under root and non-root user.
|
|
|
|
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
|
|
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
|
|
diff --git a/config.c b/config.c
|
|
index 3c5d143..c05abcd 100644
|
|
--- a/config.c
|
|
+++ b/config.c
|
|
@@ -387,9 +387,9 @@ struct config_item config_tab[] = {
|
|
GLOB_ITEM_INT("tx_timestamp_timeout", 10, 1, INT_MAX),
|
|
PORT_ITEM_INT("udp_ttl", 1, 1, 255),
|
|
PORT_ITEM_INT("udp6_scope", 0x0E, 0x00, 0x0F),
|
|
- GLOB_ITEM_STR("uds_address", "/var/run/ptp4l"),
|
|
+ GLOB_ITEM_STR("uds_address", "/var/run/ptp/ptp4l"),
|
|
PORT_ITEM_INT("uds_file_mode", UDS_FILEMODE, 0, 0777),
|
|
- GLOB_ITEM_STR("uds_ro_address", "/var/run/ptp4lro"),
|
|
+ GLOB_ITEM_STR("uds_ro_address", "/var/run/ptp/ptp4lro"),
|
|
PORT_ITEM_INT("uds_ro_file_mode", UDS_RO_FILEMODE, 0, 0777),
|
|
PORT_ITEM_INT("unicast_listen", 0, 0, 1),
|
|
PORT_ITEM_INT("unicast_master_table", 0, 0, INT_MAX),
|
|
diff --git a/configs/CMLDS_server.cfg b/configs/CMLDS_server.cfg
|
|
index 36f118c..842fbe4 100644
|
|
--- a/configs/CMLDS_server.cfg
|
|
+++ b/configs/CMLDS_server.cfg
|
|
@@ -10,7 +10,7 @@ clockIdentity C37D50.0000.000000
|
|
free_running 1
|
|
ignore_transport_specific 1
|
|
transportSpecific 2
|
|
-uds_address /var/run/cmlds_server
|
|
+uds_address /var/run/ptp/cmlds_server
|
|
|
|
[eth1]
|
|
delay_mechanism P2P
|
|
diff --git a/configs/default.cfg b/configs/default.cfg
|
|
index c3ad618..c2e0f93 100644
|
|
--- a/configs/default.cfg
|
|
+++ b/configs/default.cfg
|
|
@@ -96,11 +96,11 @@ write_phase_mode 0
|
|
#
|
|
# Transport options
|
|
#
|
|
-cmlds.client_address /var/run/cmlds_client
|
|
+cmlds.client_address /var/run/ptp/cmlds_client
|
|
cmlds.domainNumber 0
|
|
cmlds.majorSdoId 2
|
|
cmlds.port 0
|
|
-cmlds.server_address /var/run/cmlds_server
|
|
+cmlds.server_address /var/run/ptp/cmlds_server
|
|
transportSpecific 0x0
|
|
ptp_dst_ipv4 224.0.1.129
|
|
p2p_dst_ipv4 224.0.0.107
|
|
@@ -110,9 +110,9 @@ ptp_dst_mac 01:1B:19:00:00:00
|
|
p2p_dst_mac 01:80:C2:00:00:0E
|
|
udp_ttl 1
|
|
udp6_scope 0x0E
|
|
-uds_address /var/run/ptp4l
|
|
+uds_address /var/run/ptp/ptp4l
|
|
uds_file_mode 0660
|
|
-uds_ro_address /var/run/ptp4lro
|
|
+uds_ro_address /var/run/ptp/ptp4lro
|
|
uds_ro_file_mode 0666
|
|
#
|
|
# Default interface options
|
|
diff --git a/phc2sys.8 b/phc2sys.8
|
|
index 3246c8f..80d009f 100644
|
|
--- a/phc2sys.8
|
|
+++ b/phc2sys.8
|
|
@@ -224,7 +224,7 @@ Specifies the address of the server's UNIX domain socket. This option can be
|
|
used up to 16 times in the automatic mode to synchronize clocks between multiple
|
|
.B ptp4l
|
|
instances.
|
|
-The default is /var/run/ptp4l.
|
|
+The default is /var/run/ptp/ptp4l.
|
|
.TP
|
|
.BI \-l " print-level"
|
|
Set the maximum syslog level of messages which should be printed or sent to
|
|
@@ -420,7 +420,7 @@ The default is 0.
|
|
.TP
|
|
.B uds_address
|
|
Specifies the address of the server's UNIX domain socket. The default
|
|
-is /var/run/ptp4
|
|
+is /var/run/ptp/ptp4l
|
|
Same as option
|
|
.B \-z
|
|
(see above).
|
|
diff --git a/phc2sys.c b/phc2sys.c
|
|
index dd72c17..1269d18 100644
|
|
--- a/phc2sys.c
|
|
+++ b/phc2sys.c
|
|
@@ -1202,7 +1202,7 @@ static void usage(char *progname)
|
|
" -u [num] number of clock updates in summary stats (0)\n"
|
|
" -n [num] domain number (0)\n"
|
|
" -x apply leap seconds by servo instead of kernel\n"
|
|
- " -z [path] server address for UDS (/var/run/ptp4l)\n"
|
|
+ " -z [path] server address for UDS (/var/run/ptp/ptp4l)\n"
|
|
" -l [num] set the logging level to 'num' (6)\n"
|
|
" -t [tag] add tag to log messages\n"
|
|
" -m print messages to stdout\n"
|
|
diff --git a/pmc.8 b/pmc.8
|
|
index 1019d59..4fb740f 100644
|
|
--- a/pmc.8
|
|
+++ b/pmc.8
|
|
@@ -87,7 +87,7 @@ Domain socket is relative to the directory of the server's socket.
|
|
.TP
|
|
.BI \-s " uds-address"
|
|
Specifies the address of the server's UNIX domain socket.
|
|
-The default is /var/run/ptp4l.
|
|
+The default is /var/run/ptp/ptp4l.
|
|
.TP
|
|
.BI \-t " transport-specific-field"
|
|
Specify the transport specific field in sent messages as a hexadecimal number.
|
|
diff --git a/pmc.c b/pmc.c
|
|
index c75879f..df6bdec 100644
|
|
--- a/pmc.c
|
|
+++ b/pmc.c
|
|
@@ -706,7 +706,7 @@ static void usage(char *progname)
|
|
" -h prints this message and exits\n"
|
|
" -i [dev] interface device to use, default 'eth0'\n"
|
|
" for network and 'pmc.$pid' for UDS.\n"
|
|
- " -s [path] server address for UDS, default '/var/run/ptp4l'.\n"
|
|
+ " -s [path] server address for UDS, default '/var/run/ptp/ptp4l'.\n"
|
|
" -t [hex] transport specific field, default 0x0\n"
|
|
" -v prints the software version and exits\n"
|
|
" -z send zero length TLV values with the GET actions\n"
|
|
diff --git a/ptp4l.8 b/ptp4l.8
|
|
index a302997..d66843f 100644
|
|
--- a/ptp4l.8
|
|
+++ b/ptp4l.8
|
|
@@ -1043,7 +1043,7 @@ Specifies the address of the UNIX domain socket for receiving local
|
|
management messages. The directory containing the socket will be created on
|
|
start if it does not exist, with owner set to the user specified by the
|
|
.B user
|
|
-option. The default is /var/run/ptp4l.
|
|
+option. The default is /var/run/ptp/ptp4l.
|
|
|
|
.TP
|
|
.B uds_file_mode
|
|
@@ -1056,7 +1056,7 @@ should start with a 0 literal. The default mode is 0660.
|
|
Specifies the address of the second UNIX domain socket for receiving local
|
|
management messages, which is restricted to GET actions and does not forward
|
|
messages to other ports. Access to this socket can be given to untrusted
|
|
-applications for monitoring purposes. The default is /var/run/ptp4lro.
|
|
+applications for monitoring purposes. The default is /var/run/ptp/ptp4lro.
|
|
|
|
.TP
|
|
.B uds_ro_file_mode
|
|
|
|
commit b2e854f1ea5d97360142cf8423fe9c08cd6d5747
|
|
Author: Miroslav Lichvar (via linuxptp-devel Mailing List) <linuxptp-devel@lists.nwtime.org>
|
|
Date: Thu Jul 31 11:35:50 2025 +0200
|
|
|
|
clock: Create compatibility symlinks for UDS.
|
|
|
|
If using the new default UDS-RW/RO addresses, create symlinks at the
|
|
original location for compatibility with non-linuxptp clients and
|
|
scripts. This works only when ptp4l is not configured to drop root
|
|
privileges, otherwise it will not be able to respond to a socket owned
|
|
by root.
|
|
|
|
Don't call unlink() to remove an existing socket before trying to create
|
|
the symlink. It might be a different ptp4l instance still running. Print
|
|
a warning message if the path is not already a symlink and the symlink
|
|
cannot be created.
|
|
|
|
Suggested-by: Martin Pecka <peckama2@fel.cvut.cz>
|
|
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
|
|
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
|
|
diff --git a/clock.c b/clock.c
|
|
index 7ffdbaa..17484d8 100644
|
|
--- a/clock.c
|
|
+++ b/clock.c
|
|
@@ -24,6 +24,7 @@
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/queue.h>
|
|
+#include <sys/stat.h>
|
|
|
|
#include "address.h"
|
|
#include "bmc.h"
|
|
@@ -1104,6 +1105,16 @@ int clock_required_modes(struct clock *c)
|
|
return required_modes;
|
|
}
|
|
|
|
+static void create_symlink(const char *target, const char *path)
|
|
+{
|
|
+ struct stat st;
|
|
+
|
|
+ if (!lstat(path, &st) && (st.st_mode & S_IFMT) == S_IFLNK)
|
|
+ return;
|
|
+ if (symlink(target, path))
|
|
+ pr_warning("failed to create symlink %s->%s: %m", path, target);
|
|
+}
|
|
+
|
|
struct clock *clock_create(enum clock_type type, struct config *config,
|
|
const char *phc_device)
|
|
{
|
|
@@ -1268,9 +1279,14 @@ struct clock *clock_create(enum clock_type type, struct config *config,
|
|
}
|
|
}
|
|
|
|
- /* Configure the UDS. */
|
|
+ /*
|
|
+ * Configure the UDS ports. If using the new default server addresses,
|
|
+ * create also symlinks for compatibility with older clients.
|
|
+ */
|
|
|
|
uds_ifname = config_get_string(config, NULL, "uds_address");
|
|
+ if (!strcmp(uds_ifname, "/var/run/ptp/ptp4l"))
|
|
+ create_symlink("ptp/ptp4l", "/var/run/ptp4l");
|
|
c->uds_rw_if = interface_create(uds_ifname, NULL);
|
|
if (config_set_section_int(config, interface_name(c->uds_rw_if),
|
|
"announceReceiptTimeout", 0)) {
|
|
@@ -1291,6 +1307,8 @@ struct clock *clock_create(enum clock_type type, struct config *config,
|
|
|
|
uds_ifname = config_get_string(config, NULL, "uds_ro_address");
|
|
c->uds_ro_if = interface_create(uds_ifname, NULL);
|
|
+ if (!strcmp(uds_ifname, "/var/run/ptp/ptp4lro"))
|
|
+ create_symlink("ptp/ptp4lro", "/var/run/ptp4lro");
|
|
if (config_set_section_int(config, interface_name(c->uds_ro_if),
|
|
"announceReceiptTimeout", 0)) {
|
|
return NULL;
|
|
commit b5ea7e569e308f8bb69160f86c3e341572166c3d
|
|
Author: Miroslav Lichvar <mlichvar@redhat.com>
|
|
Date: Thu Oct 2 13:09:32 2025 +0200
|
|
|
|
pmc_agent: Keep pmc_ds_requested set across run_pmc() calls.
|
|
|
|
In the handling of timeout in run_pmc() the pmc_ds_requested variable is
|
|
always cleared to force the next call of the function to send a new
|
|
request if a response is not received in that time. This prevents
|
|
detection of a missed response as nothing is tracking if a request was
|
|
sent in the previous call. The variable is also set in run_pmc_wait_sync()
|
|
to avoid sending a new request when waiting multiple port-specific
|
|
responses.
|
|
|
|
Modify the function to accept a new parameter enabling the receive-only
|
|
mode and keep the pmc_ds_requested variable set on the timeout to make
|
|
it clear when a response is missing, which will be needed in the next
|
|
commit to reopen the transport.
|
|
|
|
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
|
|
|
|
diff --git a/pmc_agent.c b/pmc_agent.c
|
|
index 663adc0..70d46cf 100644
|
|
--- a/pmc_agent.c
|
|
+++ b/pmc_agent.c
|
|
@@ -136,16 +136,16 @@ static int run_pmc_err2errno(int code)
|
|
}
|
|
|
|
static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
|
|
- struct ptp_message **msg)
|
|
+ int recv_only, struct ptp_message **msg)
|
|
{
|
|
#define N_FD 1
|
|
struct pollfd pollfd[N_FD];
|
|
- int cnt, res;
|
|
+ int cnt, res, req_sent = 0;
|
|
|
|
while (1) {
|
|
pollfd[0].fd = pmc_get_transport_fd(node->pmc);
|
|
pollfd[0].events = POLLIN|POLLPRI;
|
|
- if (!node->pmc_ds_requested && ds_id >= 0)
|
|
+ if (!recv_only && !req_sent && ds_id >= 0)
|
|
pollfd[0].events |= POLLOUT;
|
|
|
|
cnt = poll(pollfd, N_FD, timeout);
|
|
@@ -154,8 +154,7 @@ static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
|
|
return RUN_PMC_INTR;
|
|
}
|
|
if (!cnt) {
|
|
- /* Request the data set again in the next run. */
|
|
- node->pmc_ds_requested = 0;
|
|
+ pr_debug("poll timeout");
|
|
return RUN_PMC_TMO;
|
|
}
|
|
|
|
@@ -171,6 +170,7 @@ static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
|
|
break;
|
|
}
|
|
node->pmc_ds_requested = 1;
|
|
+ req_sent = 1;
|
|
}
|
|
|
|
if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
|
|
@@ -209,7 +209,7 @@ static int renew_subscription(struct pmc_agent *node, int timeout)
|
|
struct ptp_message *msg;
|
|
int res;
|
|
|
|
- res = run_pmc(node, timeout, MID_SUBSCRIBE_EVENTS_NP, &msg);
|
|
+ res = run_pmc(node, timeout, MID_SUBSCRIBE_EVENTS_NP, 0, &msg);
|
|
if (is_run_pmc_error(res)) {
|
|
return run_pmc_err2errno(res);
|
|
}
|
|
@@ -221,11 +221,11 @@ int run_pmc_wait_sync(struct pmc_agent *node, int timeout)
|
|
{
|
|
struct ptp_message *msg;
|
|
Enumeration8 portState;
|
|
+ int res, recv_only = 0;
|
|
void *data;
|
|
- int res;
|
|
|
|
while (1) {
|
|
- res = run_pmc(node, timeout, MID_PORT_DATA_SET, &msg);
|
|
+ res = run_pmc(node, timeout, MID_PORT_DATA_SET, recv_only, &msg);
|
|
if (res <= 0)
|
|
return res;
|
|
|
|
@@ -239,7 +239,7 @@ int run_pmc_wait_sync(struct pmc_agent *node, int timeout)
|
|
return 1;
|
|
}
|
|
/* try to get more data sets (for other ports) */
|
|
- node->pmc_ds_requested = 1;
|
|
+ recv_only = 1;
|
|
}
|
|
}
|
|
|
|
@@ -307,7 +307,7 @@ int pmc_agent_query_dds(struct pmc_agent *node, int timeout)
|
|
struct defaultDS *dds;
|
|
int res;
|
|
|
|
- res = run_pmc(node, timeout, MID_DEFAULT_DATA_SET, &msg);
|
|
+ res = run_pmc(node, timeout, MID_DEFAULT_DATA_SET, 0, &msg);
|
|
if (is_run_pmc_error(res)) {
|
|
return run_pmc_err2errno(res);
|
|
}
|
|
@@ -325,11 +325,12 @@ int pmc_agent_query_port_properties(struct pmc_agent *node, int timeout,
|
|
struct port_properties_np *ppn;
|
|
struct port_hwclock_np *phn;
|
|
struct ptp_message *msg;
|
|
- int res, len;
|
|
+ int res, len, recv_only = 1;
|
|
|
|
pmc_target_port(node->pmc, port);
|
|
- while (1) {
|
|
- res = run_pmc(node, timeout, MID_PORT_PROPERTIES_NP, &msg);
|
|
+ for (recv_only = 0; ; recv_only = 1) {
|
|
+ res = run_pmc(node, timeout, MID_PORT_PROPERTIES_NP, recv_only,
|
|
+ &msg);
|
|
if (is_run_pmc_error(res)) {
|
|
goto out;
|
|
}
|
|
@@ -350,8 +351,9 @@ int pmc_agent_query_port_properties(struct pmc_agent *node, int timeout,
|
|
msg_put(msg);
|
|
break;
|
|
}
|
|
- while (1) {
|
|
- res = run_pmc(node, timeout, MID_PORT_HWCLOCK_NP, &msg);
|
|
+ for (recv_only = 0; ; recv_only = 1) {
|
|
+ res = run_pmc(node, timeout, MID_PORT_HWCLOCK_NP, recv_only,
|
|
+ &msg);
|
|
if (is_run_pmc_error(res)) {
|
|
goto out;
|
|
}
|
|
@@ -377,7 +379,7 @@ int pmc_agent_query_utc_offset(struct pmc_agent *node, int timeout)
|
|
struct ptp_message *msg;
|
|
int res;
|
|
|
|
- res = run_pmc(node, timeout, MID_TIME_PROPERTIES_DATA_SET, &msg);
|
|
+ res = run_pmc(node, timeout, MID_TIME_PROPERTIES_DATA_SET, 0, &msg);
|
|
if (is_run_pmc_error(res)) {
|
|
return run_pmc_err2errno(res);
|
|
}
|
|
@@ -450,7 +452,7 @@ int pmc_agent_update(struct pmc_agent *node)
|
|
break;
|
|
}
|
|
} else {
|
|
- run_pmc(node, 0, -1, &msg);
|
|
+ run_pmc(node, 0, -1, 1, &msg);
|
|
}
|
|
|
|
return 0;
|
|
|
|
commit fc0df58aec568121bde53781fb7d16f3dd0b9389
|
|
Author: Miroslav Lichvar <mlichvar@redhat.com>
|
|
Date: Thu Oct 2 13:57:53 2025 +0200
|
|
|
|
pmc_agent: Reopen transport after missed response.
|
|
|
|
If the pmc agent (used in phc2sys and ts2phc) was started as root before
|
|
ptp4l configured to not run as root could bind its socket, the client
|
|
socket owner was not changed to follow the server socket, which caused
|
|
the non-privileged server to not be able to send responses to the
|
|
client.
|
|
|
|
Add a new function to pmc_common to allow reopening the transport
|
|
without destroying the pmc instance, and call it in the agent when a
|
|
response from ptp4l is missed. This allows the client to correct the
|
|
socket owner if it was started too soon in order to receive responses
|
|
from the server. It also allows the client to recover if its socket is
|
|
inadvertently removed.
|
|
|
|
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
|
|
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
|
|
|
|
diff --git a/pmc_agent.c b/pmc_agent.c
|
|
index 70d46cf..51ef61e 100644
|
|
--- a/pmc_agent.c
|
|
+++ b/pmc_agent.c
|
|
@@ -144,6 +144,12 @@ static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
|
|
|
|
while (1) {
|
|
pollfd[0].fd = pmc_get_transport_fd(node->pmc);
|
|
+ if (pollfd[0].fd < 0) {
|
|
+ if (pmc_reopen_transport(node->pmc))
|
|
+ return RUN_PMC_NODEV;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
pollfd[0].events = POLLIN|POLLPRI;
|
|
if (!recv_only && !req_sent && ds_id >= 0)
|
|
pollfd[0].events |= POLLOUT;
|
|
@@ -161,6 +167,12 @@ static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
|
|
/* Send a new request if there are no pending messages. */
|
|
if ((pollfd[0].revents & POLLOUT) &&
|
|
!(pollfd[0].revents & (POLLIN|POLLPRI))) {
|
|
+ /* Reopen the transport if a response was missed. */
|
|
+ if (node->pmc_ds_requested) {
|
|
+ if (pmc_reopen_transport(node->pmc))
|
|
+ return RUN_PMC_NODEV;
|
|
+ }
|
|
+
|
|
switch (ds_id) {
|
|
case MID_SUBSCRIBE_EVENTS_NP:
|
|
send_subscription(node);
|
|
diff --git a/pmc_common.c b/pmc_common.c
|
|
index a67b01f..246aeb3 100644
|
|
--- a/pmc_common.c
|
|
+++ b/pmc_common.c
|
|
@@ -597,11 +597,10 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type,
|
|
goto failed;
|
|
}
|
|
|
|
- if (transport_open(pmc->transport, pmc->iface,
|
|
- &pmc->fdarray, TS_SOFTWARE)) {
|
|
- pr_err("failed to open transport");
|
|
+ pmc->fdarray.fd[FD_GENERAL] = -1;
|
|
+ if (pmc_reopen_transport(pmc))
|
|
goto no_trans_open;
|
|
- }
|
|
+
|
|
pmc->zero_length_gets = zero_datalen ? 1 : 0;
|
|
|
|
return pmc;
|
|
@@ -615,6 +614,23 @@ failed:
|
|
return NULL;
|
|
}
|
|
|
|
+int pmc_reopen_transport(struct pmc *pmc)
|
|
+{
|
|
+ pr_debug("(re)opening transport");
|
|
+
|
|
+ if (pmc_get_transport_fd(pmc) >= 0)
|
|
+ transport_close(pmc->transport, &pmc->fdarray);
|
|
+ pmc->fdarray.fd[FD_GENERAL] = -1;
|
|
+
|
|
+ if (transport_open(pmc->transport, pmc->iface,
|
|
+ &pmc->fdarray, TS_SOFTWARE)) {
|
|
+ pr_err("failed to open transport");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
void pmc_destroy(struct pmc *pmc)
|
|
{
|
|
transport_close(pmc->transport, &pmc->fdarray);
|
|
diff --git a/pmc_common.h b/pmc_common.h
|
|
index 7b76061..93701fb 100644
|
|
--- a/pmc_common.h
|
|
+++ b/pmc_common.h
|
|
@@ -34,6 +34,8 @@ struct pmc *pmc_create(struct config *cfg, enum transport_type transport_type,
|
|
UInteger8 transport_specific, UInteger8 allow_unauth,
|
|
int zero_datalen);
|
|
|
|
+int pmc_reopen_transport(struct pmc *pmc);
|
|
+
|
|
void pmc_destroy(struct pmc *pmc);
|
|
|
|
int pmc_get_transport_fd(struct pmc *pmc);
|