diff --git a/linuxptp-udsro.patch b/linuxptp-udsro.patch
new file mode 100644
index 0000000..7030553
--- /dev/null
+++ b/linuxptp-udsro.patch
@@ -0,0 +1,614 @@
+Patches backported from the upstream repository.
+
+commit acc045034dd0db9dd4c4aca4b26528f8fed2ae78
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Thu Feb 11 16:47:08 2021 +0100
+
+    port: Ignore non-management messages on UDS port.
+    
+    Drop non-management messages on the UDS port early in the processing to
+    prevent them from changing the port or clock state.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/port.c b/port.c
+index fa49663..3fd06b1 100644
+--- a/port.c
++++ b/port.c
+@@ -56,6 +56,7 @@ enum syfu_event {
+ };
+ 
+ static int port_is_ieee8021as(struct port *p);
++static int port_is_uds(struct port *p);
+ static void port_nrate_initialize(struct port *p);
+ 
+ static int announce_compare(struct ptp_message *m1, struct ptp_message *m2)
+@@ -691,6 +692,9 @@ static int port_ignore(struct port *p, struct ptp_message *m)
+ {
+ 	struct ClockIdentity c1, c2;
+ 
++	if (port_is_uds(p) && msg_type(m) != MANAGEMENT) {
++		return 1;
++	}
+ 	if (incapable_ignore(p, m)) {
+ 		return 1;
+ 	}
+@@ -771,6 +775,11 @@ static int port_is_ieee8021as(struct port *p)
+ 	return p->follow_up_info ? 1 : 0;
+ }
+ 
++static int port_is_uds(struct port *p)
++{
++	return transport_type(p->trp) == TRANS_UDS;
++}
++
+ static void port_management_send_error(struct port *p, struct port *ingress,
+ 				       struct ptp_message *msg, int error_id)
+ {
+
+commit 72ec806fa62a87cb7e5444e27fa6bdcbfe4e27ca
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Thu Feb 11 16:47:09 2021 +0100
+
+    clock: Don't allow COMMAND action on non-UDS port.
+    
+    No COMMAND actions are currently supported, but check the port early in
+    clock_manage() before reaching port_manage().
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/clock.c b/clock.c
+index a66d189..a6947bc 100644
+--- a/clock.c
++++ b/clock.c
+@@ -1423,6 +1423,11 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
+ 			return changed;
+ 		break;
+ 	case COMMAND:
++		if (p != c->uds_port) {
++			/* Sorry, only allowed on the UDS port. */
++			clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
++			return changed;
++		}
+ 		break;
+ 	default:
+ 		return changed;
+
+commit 2b45d80eadcb81c8bdf45baf98dabeebd912b1b0
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Thu Feb 11 16:47:10 2021 +0100
+
+    clock: Rename UDS variables to read-write.
+    
+    In preparation for a new read-only UDS port, rename variables of the
+    current UDS port to make it clear it is read-write, as opposed to
+    read-only.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/clock.c b/clock.c
+index a6947bc..d013b19 100644
+--- a/clock.c
++++ b/clock.c
+@@ -95,7 +95,7 @@ struct clock {
+ 	struct foreign_clock *best;
+ 	struct ClockIdentity best_id;
+ 	LIST_HEAD(ports_head, port) ports;
+-	struct port *uds_port;
++	struct port *uds_rw_port;
+ 	struct pollfd *pollfd;
+ 	int pollfd_valid;
+ 	int nports; /* does not include the UDS port */
+@@ -129,7 +129,7 @@ struct clock {
+ 	struct clock_stats stats;
+ 	int stats_interval;
+ 	struct clockcheck *sanity_check;
+-	struct interface *udsif;
++	struct interface *uds_rw_if;
+ 	LIST_HEAD(clock_subscribers_head, clock_subscriber) subscribers;
+ 	struct monitor *slave_event_monitor;
+ };
+@@ -245,7 +245,7 @@ void clock_send_notification(struct clock *c, struct ptp_message *msg,
+ {
+ 	unsigned int event_pos = event / 8;
+ 	uint8_t mask = 1 << (event % 8);
+-	struct port *uds = c->uds_port;
++	struct port *uds = c->uds_rw_port;
+ 	struct clock_subscriber *s;
+ 
+ 	LIST_FOREACH(s, &c->subscribers, list) {
+@@ -267,13 +267,13 @@ void clock_destroy(struct clock *c)
+ {
+ 	struct port *p, *tmp;
+ 
+-	interface_destroy(c->udsif);
++	interface_destroy(c->uds_rw_if);
+ 	clock_flush_subscriptions(c);
+ 	LIST_FOREACH_SAFE(p, &c->ports, list, tmp) {
+ 		clock_remove_port(c, p);
+ 	}
+ 	monitor_destroy(c->slave_event_monitor);
+-	port_close(c->uds_port);
++	port_close(c->uds_rw_port);
+ 	free(c->pollfd);
+ 	if (c->clkid != CLOCK_REALTIME) {
+ 		phc_close(c->clkid);
+@@ -442,7 +442,7 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
+ 		datalen = sizeof(*gsn);
+ 		break;
+ 	case TLV_SUBSCRIBE_EVENTS_NP:
+-		if (p != c->uds_port) {
++		if (p != c->uds_rw_port) {
+ 			/* Only the UDS port allowed. */
+ 			break;
+ 		}
+@@ -784,7 +784,7 @@ static int forwarding(struct clock *c, struct port *p)
+ 	default:
+ 		break;
+ 	}
+-	if (p == c->uds_port && ps != PS_FAULTY) {
++	if (p == c->uds_rw_port && ps != PS_FAULTY) {
+ 		return 1;
+ 	}
+ 	return 0;
+@@ -1044,20 +1044,20 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 
+ 	/* Configure the UDS. */
+ 	uds_ifname = config_get_string(config, NULL, "uds_address");
+-	c->udsif = interface_create(uds_ifname);
+-	if (config_set_section_int(config, interface_name(c->udsif),
++	c->uds_rw_if = interface_create(uds_ifname);
++	if (config_set_section_int(config, interface_name(c->uds_rw_if),
+ 				   "announceReceiptTimeout", 0)) {
+ 		return NULL;
+ 	}
+-	if (config_set_section_int(config, interface_name(c->udsif),
++	if (config_set_section_int(config, interface_name(c->uds_rw_if),
+ 				    "delay_mechanism", DM_AUTO)) {
+ 		return NULL;
+ 	}
+-	if (config_set_section_int(config, interface_name(c->udsif),
++	if (config_set_section_int(config, interface_name(c->uds_rw_if),
+ 				    "network_transport", TRANS_UDS)) {
+ 		return NULL;
+ 	}
+-	if (config_set_section_int(config, interface_name(c->udsif),
++	if (config_set_section_int(config, interface_name(c->uds_rw_if),
+ 				   "delay_filter_length", 1)) {
+ 		return NULL;
+ 	}
+@@ -1180,14 +1180,15 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 	}
+ 
+ 	/* Create the UDS interface. */
+-	c->uds_port = port_open(phc_device, phc_index, timestamping, 0, c->udsif, c);
+-	if (!c->uds_port) {
++	c->uds_rw_port = port_open(phc_device, phc_index, timestamping, 0,
++				   c->uds_rw_if, c);
++	if (!c->uds_rw_port) {
+ 		pr_err("failed to open the UDS port");
+ 		return NULL;
+ 	}
+ 	clock_fda_changed(c);
+ 
+-	c->slave_event_monitor = monitor_create(config, c->uds_port);
++	c->slave_event_monitor = monitor_create(config, c->uds_rw_port);
+ 	if (!c->slave_event_monitor) {
+ 		pr_err("failed to create slave event monitor");
+ 		return NULL;
+@@ -1206,7 +1207,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 	LIST_FOREACH(p, &c->ports, list) {
+ 		port_dispatch(p, EV_INITIALIZE, 0);
+ 	}
+-	port_dispatch(c->uds_port, EV_INITIALIZE, 0);
++	port_dispatch(c->uds_rw_port, EV_INITIALIZE, 0);
+ 
+ 	return c;
+ }
+@@ -1314,7 +1315,7 @@ static void clock_check_pollfd(struct clock *c)
+ 		clock_fill_pollfd(dest, p);
+ 		dest += N_CLOCK_PFD;
+ 	}
+-	clock_fill_pollfd(dest, c->uds_port);
++	clock_fill_pollfd(dest, c->uds_rw_port);
+ 	c->pollfd_valid = 1;
+ }
+ 
+@@ -1331,7 +1332,7 @@ static int clock_do_forward_mgmt(struct clock *c,
+ 		return 0;
+ 
+ 	/* Don't forward any requests to the UDS port. */
+-	if (out == c->uds_port) {
++	if (out == c->uds_rw_port) {
+ 		switch (management_action(msg)) {
+ 		case GET:
+ 		case SET:
+@@ -1362,7 +1363,7 @@ static void clock_forward_mgmt_msg(struct clock *c, struct port *p, struct ptp_m
+ 				pr_err("port %d: management forward failed",
+ 				       port_number(piter));
+ 		}
+-		if (clock_do_forward_mgmt(c, p, c->uds_port, msg, &msg_ready))
++		if (clock_do_forward_mgmt(c, p, c->uds_rw_port, msg, &msg_ready))
+ 			pr_err("uds port: management forward failed");
+ 		if (msg_ready) {
+ 			msg_post_recv(msg, pdulen);
+@@ -1414,7 +1415,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
+ 			clock_management_send_error(p, msg, TLV_WRONG_LENGTH);
+ 			return changed;
+ 		}
+-		if (p != c->uds_port) {
++		if (p != c->uds_rw_port) {
+ 			/* Sorry, only allowed on the UDS port. */
+ 			clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
+ 			return changed;
+@@ -1423,7 +1424,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
+ 			return changed;
+ 		break;
+ 	case COMMAND:
+-		if (p != c->uds_port) {
++		if (p != c->uds_rw_port) {
+ 			/* Sorry, only allowed on the UDS port. */
+ 			clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
+ 			return changed;
+@@ -1435,7 +1436,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
+ 
+ 	switch (mgt->id) {
+ 	case TLV_PORT_PROPERTIES_NP:
+-		if (p != c->uds_port) {
++		if (p != c->uds_rw_port) {
+ 			/* Only the UDS port allowed. */
+ 			clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
+ 			return 0;
+@@ -1500,7 +1501,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
+ 
+ void clock_notify_event(struct clock *c, enum notification event)
+ {
+-	struct port *uds = c->uds_port;
++	struct port *uds = c->uds_rw_port;
+ 	struct PortIdentity pid = port_identity(uds);
+ 	struct ptp_message *msg;
+ 	int id;
+@@ -1604,7 +1605,7 @@ int clock_poll(struct clock *c)
+ 	/* Check the UDS port. */
+ 	for (i = 0; i < N_POLLFD; i++) {
+ 		if (cur[i].revents & (POLLIN|POLLPRI)) {
+-			event = port_event(c->uds_port, i);
++			event = port_event(c->uds_rw_port, i);
+ 			if (EV_STATE_DECISION_EVENT == event) {
+ 				c->sde = 1;
+ 			}
+
+commit 1f74a16502b55ce8eaed3d7488542e5469ac8263
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Thu Feb 11 16:47:11 2021 +0100
+
+    clock: Add read-only UDS port for monitoring.
+    
+    Add a second UDS port to allow untrusted applications to monitor ptp4l.
+    On this "read-only" UDS port disable non-GET actions and forwarding.
+    The path can be configured with the uds_ro_address option (default is
+    /var/run/ptp4lro).
+    
+    Forwarding is disabled to limit the access to the local ptp4l instance.
+    
+    Subscriptions are not enabled to prevent the applications from making a
+    large number of subscriptions or interfere with applications that have
+    access to the read-write UDS port.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/clock.c b/clock.c
+index d013b19..8592d29 100644
+--- a/clock.c
++++ b/clock.c
+@@ -96,9 +96,10 @@ struct clock {
+ 	struct ClockIdentity best_id;
+ 	LIST_HEAD(ports_head, port) ports;
+ 	struct port *uds_rw_port;
++	struct port *uds_ro_port;
+ 	struct pollfd *pollfd;
+ 	int pollfd_valid;
+-	int nports; /* does not include the UDS port */
++	int nports; /* does not include the two UDS ports */
+ 	int last_port_number;
+ 	int sde;
+ 	int free_running;
+@@ -130,6 +131,7 @@ struct clock {
+ 	int stats_interval;
+ 	struct clockcheck *sanity_check;
+ 	struct interface *uds_rw_if;
++	struct interface *uds_ro_if;
+ 	LIST_HEAD(clock_subscribers_head, clock_subscriber) subscribers;
+ 	struct monitor *slave_event_monitor;
+ };
+@@ -268,12 +270,14 @@ void clock_destroy(struct clock *c)
+ 	struct port *p, *tmp;
+ 
+ 	interface_destroy(c->uds_rw_if);
++	interface_destroy(c->uds_ro_if);
+ 	clock_flush_subscriptions(c);
+ 	LIST_FOREACH_SAFE(p, &c->ports, list, tmp) {
+ 		clock_remove_port(c, p);
+ 	}
+ 	monitor_destroy(c->slave_event_monitor);
+ 	port_close(c->uds_rw_port);
++	port_close(c->uds_ro_port);
+ 	free(c->pollfd);
+ 	if (c->clkid != CLOCK_REALTIME) {
+ 		phc_close(c->clkid);
+@@ -443,7 +447,7 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
+ 		break;
+ 	case TLV_SUBSCRIBE_EVENTS_NP:
+ 		if (p != c->uds_rw_port) {
+-			/* Only the UDS port allowed. */
++			/* Only the UDS-RW port allowed. */
+ 			break;
+ 		}
+ 		sen = (struct subscribe_events_np *)tlv->data;
+@@ -774,6 +778,10 @@ static int clock_utc_correct(struct clock *c, tmv_t ingress)
+ static int forwarding(struct clock *c, struct port *p)
+ {
+ 	enum port_state ps = port_state(p);
++
++	if (p == c->uds_ro_port)
++		return 0;
++
+ 	switch (ps) {
+ 	case PS_MASTER:
+ 	case PS_GRAND_MASTER:
+@@ -818,7 +826,7 @@ static int clock_add_port(struct clock *c, const char *phc_device,
+ {
+ 	struct port *p, *piter, *lastp = NULL;
+ 
+-	if (clock_resize_pollfd(c, c->nports + 1)) {
++	if (clock_resize_pollfd(c, c->nports + 2)) {
+ 		return -1;
+ 	}
+ 	p = port_open(phc_device, phc_index, timestamping,
+@@ -1043,6 +1051,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 	}
+ 
+ 	/* Configure the UDS. */
++
+ 	uds_ifname = config_get_string(config, NULL, "uds_address");
+ 	c->uds_rw_if = interface_create(uds_ifname);
+ 	if (config_set_section_int(config, interface_name(c->uds_rw_if),
+@@ -1062,6 +1071,25 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 		return NULL;
+ 	}
+ 
++	uds_ifname = config_get_string(config, NULL, "uds_ro_address");
++	c->uds_ro_if = interface_create(uds_ifname);
++	if (config_set_section_int(config, interface_name(c->uds_ro_if),
++				   "announceReceiptTimeout", 0)) {
++		return NULL;
++	}
++	if (config_set_section_int(config, interface_name(c->uds_ro_if),
++				   "delay_mechanism", DM_AUTO)) {
++		return NULL;
++	}
++	if (config_set_section_int(config, interface_name(c->uds_ro_if),
++				   "network_transport", TRANS_UDS)) {
++		return NULL;
++	}
++	if (config_set_section_int(config, interface_name(c->uds_ro_if),
++				   "delay_filter_length", 1)) {
++		return NULL;
++	}
++
+ 	c->config = config;
+ 	c->free_running = config_get_int(config, NULL, "free_running");
+ 	c->freq_est_interval = config_get_int(config, NULL, "freq_est_interval");
+@@ -1179,11 +1207,18 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 		return NULL;
+ 	}
+ 
+-	/* Create the UDS interface. */
++	/* Create the UDS interfaces. */
++
+ 	c->uds_rw_port = port_open(phc_device, phc_index, timestamping, 0,
+ 				   c->uds_rw_if, c);
+ 	if (!c->uds_rw_port) {
+-		pr_err("failed to open the UDS port");
++		pr_err("failed to open the UDS-RW port");
++		return NULL;
++	}
++	c->uds_ro_port = port_open(phc_device, phc_index, timestamping, 0,
++				   c->uds_ro_if, c);
++	if (!c->uds_ro_port) {
++		pr_err("failed to open the UDS-RO port");
+ 		return NULL;
+ 	}
+ 	clock_fda_changed(c);
+@@ -1208,6 +1243,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
+ 		port_dispatch(p, EV_INITIALIZE, 0);
+ 	}
+ 	port_dispatch(c->uds_rw_port, EV_INITIALIZE, 0);
++	port_dispatch(c->uds_ro_port, EV_INITIALIZE, 0);
+ 
+ 	return c;
+ }
+@@ -1278,9 +1314,9 @@ static int clock_resize_pollfd(struct clock *c, int new_nports)
+ {
+ 	struct pollfd *new_pollfd;
+ 
+-	/* Need to allocate one whole extra block of fds for UDS. */
++	/* Need to allocate two whole extra blocks of fds for UDS ports. */
+ 	new_pollfd = realloc(c->pollfd,
+-			     (new_nports + 1) * N_CLOCK_PFD *
++			     (new_nports + 2) * N_CLOCK_PFD *
+ 			     sizeof(struct pollfd));
+ 	if (!new_pollfd) {
+ 		return -1;
+@@ -1316,6 +1352,8 @@ static void clock_check_pollfd(struct clock *c)
+ 		dest += N_CLOCK_PFD;
+ 	}
+ 	clock_fill_pollfd(dest, c->uds_rw_port);
++	dest += N_CLOCK_PFD;
++	clock_fill_pollfd(dest, c->uds_ro_port);
+ 	c->pollfd_valid = 1;
+ }
+ 
+@@ -1331,7 +1369,8 @@ static int clock_do_forward_mgmt(struct clock *c,
+ 	if (in == out || !forwarding(c, out))
+ 		return 0;
+ 
+-	/* Don't forward any requests to the UDS port. */
++	/* Don't forward any requests to the UDS-RW port
++	   (the UDS-RO port doesn't allow any forwarding). */
+ 	if (out == c->uds_rw_port) {
+ 		switch (management_action(msg)) {
+ 		case GET:
+@@ -1416,7 +1455,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
+ 			return changed;
+ 		}
+ 		if (p != c->uds_rw_port) {
+-			/* Sorry, only allowed on the UDS port. */
++			/* Sorry, only allowed on the UDS-RW port. */
+ 			clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
+ 			return changed;
+ 		}
+@@ -1425,7 +1464,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
+ 		break;
+ 	case COMMAND:
+ 		if (p != c->uds_rw_port) {
+-			/* Sorry, only allowed on the UDS port. */
++			/* Sorry, only allowed on the UDS-RW port. */
+ 			clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
+ 			return changed;
+ 		}
+@@ -1437,7 +1476,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
+ 	switch (mgt->id) {
+ 	case TLV_PORT_PROPERTIES_NP:
+ 		if (p != c->uds_rw_port) {
+-			/* Only the UDS port allowed. */
++			/* Only the UDS-RW port allowed. */
+ 			clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
+ 			return 0;
+ 		}
+@@ -1548,7 +1587,7 @@ int clock_poll(struct clock *c)
+ 	struct port *p;
+ 
+ 	clock_check_pollfd(c);
+-	cnt = poll(c->pollfd, (c->nports + 1) * N_CLOCK_PFD, -1);
++	cnt = poll(c->pollfd, (c->nports + 2) * N_CLOCK_PFD, -1);
+ 	if (cnt < 0) {
+ 		if (EINTR == errno) {
+ 			return 0;
+@@ -1602,7 +1641,7 @@ int clock_poll(struct clock *c)
+ 		cur += N_CLOCK_PFD;
+ 	}
+ 
+-	/* Check the UDS port. */
++	/* Check the UDS ports. */
+ 	for (i = 0; i < N_POLLFD; i++) {
+ 		if (cur[i].revents & (POLLIN|POLLPRI)) {
+ 			event = port_event(c->uds_rw_port, i);
+@@ -1611,6 +1650,13 @@ int clock_poll(struct clock *c)
+ 			}
+ 		}
+ 	}
++	cur += N_CLOCK_PFD;
++	for (i = 0; i < N_POLLFD; i++) {
++		if (cur[i].revents & (POLLIN|POLLPRI)) {
++			event = port_event(c->uds_ro_port, i);
++			/* sde is not expected on the UDS-RO port */
++		}
++	}
+ 
+ 	if (c->sde) {
+ 		handle_state_decision_event(c);
+diff --git a/config.c b/config.c
+index d237de9..96a5351 100644
+--- a/config.c
++++ b/config.c
+@@ -323,6 +323,7 @@ struct config_item config_tab[] = {
+ 	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_ro_address", "/var/run/ptp4lro"),
+ 	PORT_ITEM_INT("unicast_listen", 0, 0, 1),
+ 	PORT_ITEM_INT("unicast_master_table", 0, 0, INT_MAX),
+ 	PORT_ITEM_INT("unicast_req_duration", 3600, 10, INT_MAX),
+diff --git a/configs/default.cfg b/configs/default.cfg
+index 8c19129..d5bab7d 100644
+--- a/configs/default.cfg
++++ b/configs/default.cfg
+@@ -90,6 +90,7 @@ p2p_dst_mac		01:80:C2:00:00:0E
+ udp_ttl			1
+ udp6_scope		0x0E
+ uds_address		/var/run/ptp4l
++uds_ro_address		/var/run/ptp4lro
+ #
+ # Default interface options
+ #
+diff --git a/ptp4l.8 b/ptp4l.8
+index b179b81..f9bd228 100644
+--- a/ptp4l.8
++++ b/ptp4l.8
+@@ -615,6 +615,12 @@ is only relevant with IPv6 transport.  See RFC 4291.  The default is
+ Specifies the address of the UNIX domain socket for receiving local
+ management messages. The default is /var/run/ptp4l.
+ .TP
++.B uds_ro_address
++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.
++.TP
+ .B dscp_event
+ Defines the Differentiated Services Codepoint (DSCP) to be used for PTP
+ event messages. Must be a value between 0 and 63. There are several media
+
+commit d4c5343237588d265c605f3772337bc88cabe787
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date:   Thu Feb 11 16:47:12 2021 +0100
+
+    timemaster: Set uds_ro_address for ptp4l instances.
+    
+    This prevents conflicts on the new UDS-RO port.
+    
+    Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
+
+diff --git a/timemaster.c b/timemaster.c
+index 00db59f..02408d6 100644
+--- a/timemaster.c
++++ b/timemaster.c
+@@ -712,7 +712,7 @@ static int add_ptp_source(struct ptp_domain *source,
+ 			  char **ntp_config, struct script *script)
+ {
+ 	struct config_file *config_file;
+-	char **command, *uds_path, **interfaces, *message_tag;
++	char **command, *uds_path, *uds_path2, **interfaces, *message_tag;
+ 	char ts_interface[IF_NAMESIZE];
+ 	int i, j, num_interfaces, *phc, *phcs, hw_ts, sw_ts;
+ 	struct sk_ts_info ts_info;
+@@ -809,6 +809,8 @@ static int add_ptp_source(struct ptp_domain *source,
+ 
+ 		uds_path = string_newf("%s/ptp4l.%d.socket",
+ 				       config->rundir, *shm_segment);
++		uds_path2 = string_newf("%s/ptp4lro.%d.socket",
++					config->rundir, *shm_segment);
+ 
+ 		message_tag = string_newf("[%d", source->domain);
+ 		for (j = 0; interfaces[j]; j++)
+@@ -832,8 +834,10 @@ static int add_ptp_source(struct ptp_domain *source,
+ 			       "slaveOnly 1\n"
+ 			       "domainNumber %d\n"
+ 			       "uds_address %s\n"
++			       "uds_ro_address %s\n"
+ 			       "message_tag %s\n",
+-			       source->domain, uds_path, message_tag);
++			       source->domain, uds_path, uds_path2,
++			       message_tag);
+ 
+ 		if (phcs[i] >= 0) {
+ 			/* HW time stamping */
+@@ -868,6 +872,7 @@ static int add_ptp_source(struct ptp_domain *source,
+ 
+ 		free(message_tag);
+ 		free(uds_path);
++		free(uds_path2);
+ 		free(interfaces);
+ 	}
+ 
diff --git a/linuxptp.spec b/linuxptp.spec
index 5f92aac..c8b67a1 100644
--- a/linuxptp.spec
+++ b/linuxptp.spec
@@ -29,6 +29,8 @@ Patch2:		linuxptp-classthreshold.patch
 Patch3:		linuxptp-deftxtout.patch
 # limit unicast message rate per address and grant duration
 Patch4:		linuxptp-ucastrate.patch
+# add read-only UDS port
+Patch5:		linuxptp-udsro.patch
 # fix quoting in ptp4l man page
 Patch7:		linuxptp-manfix.patch
 # close lstab file after use
@@ -55,6 +57,7 @@ Supporting legacy APIs and other platforms is not a goal.
 %patch2 -p1 -b .classthreshold
 %patch3 -p1 -b .deftxtout
 %patch4 -p1 -b .ucastrate
+%patch5 -p1 -b .udsro
 %patch7 -p1 -b .manfix
 %patch8 -p1 -b .fclose
 %patch9 -p1 -b .zerolength