1 /*
2  * Copyright (c) 2024 BayLibre SAS
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(ptp_transport, CONFIG_PTP_LOG_LEVEL);
9 
10 #include <zephyr/kernel.h>
11 
12 #include <zephyr/net/socket.h>
13 
14 #include "transport.h"
15 
16 #define INTERFACE_NAME_LEN (32)
17 
18 #if CONFIG_PTP_UDP_IPv4_PROTOCOL
19 static struct in_addr mcast_addr = {{{224, 0, 1, 129}}};
20 #elif CONFIG_PTP_UDP_IPv6_PROTOCOL
21 static struct in6_addr mcast_addr = {{{0xff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
22 				       0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x81}}};
23 #else
24 #error "Chosen PTP transport protocol not implemented"
25 #endif
26 
transport_socket_open(struct net_if * iface,struct sockaddr * addr)27 static int transport_socket_open(struct net_if *iface, struct sockaddr *addr)
28 {
29 	static const int feature_on = 1;
30 	static const uint8_t priority = NET_PRIORITY_CA;
31 	static const uint8_t ts_mask = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
32 	struct ifreq ifreq = { 0 };
33 	int cnt;
34 	int socket = zsock_socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
35 
36 	if (net_if_get_by_iface(iface) < 0) {
37 		LOG_ERR("Failed to obtain interface index");
38 		return -1;
39 	}
40 
41 	if (socket < 0) {
42 		return -1;
43 	}
44 
45 	if (zsock_setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &feature_on, sizeof(feature_on))) {
46 		LOG_ERR("Failed to set SO_REUSEADDR");
47 		goto error;
48 	}
49 
50 	if (zsock_bind(socket, addr, sizeof(*addr))) {
51 		LOG_ERR("Failed to bind socket");
52 		goto error;
53 	}
54 
55 	cnt = net_if_get_name(iface, ifreq.ifr_name, INTERFACE_NAME_LEN);
56 	if (cnt > 0 && zsock_setsockopt(socket,
57 					SOL_SOCKET,
58 					SO_BINDTODEVICE,
59 					ifreq.ifr_name,
60 					sizeof(ifreq.ifr_name))) {
61 		LOG_ERR("Failed to set socket binding to an interface");
62 		goto error;
63 	}
64 
65 	if (zsock_setsockopt(socket, SOL_SOCKET, SO_TIMESTAMPING, &ts_mask, sizeof(ts_mask))) {
66 		LOG_ERR("Failed to set SO_TIMESTAMPING");
67 		goto error;
68 	}
69 
70 	if (zsock_setsockopt(socket, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority))) {
71 		LOG_ERR("Failed to set SO_PRIORITY");
72 		goto error;
73 	}
74 
75 	return socket;
76 error:
77 	zsock_close(socket);
78 	return -1;
79 }
80 
transport_join_multicast(struct ptp_port * port)81 static int transport_join_multicast(struct ptp_port *port)
82 {
83 	if (IS_ENABLED(CONFIG_PTP_UDP_IPv4_PROTOCOL)) {
84 		struct ip_mreqn mreqn = {0};
85 
86 		memcpy(&mreqn.imr_multiaddr, &mcast_addr, sizeof(struct in_addr));
87 		mreqn.imr_ifindex = net_if_get_by_iface(port->iface);
88 
89 		zsock_setsockopt(port->socket[1], IPPROTO_IP,
90 				 IP_ADD_MEMBERSHIP, &mreqn, sizeof(mreqn));
91 	} else {
92 		struct ipv6_mreq mreqn = {0};
93 
94 		memcpy(&mreqn.ipv6mr_multiaddr, &mcast_addr, sizeof(struct in6_addr));
95 		mreqn.ipv6mr_ifindex = net_if_get_by_iface(port->iface);
96 
97 		zsock_setsockopt(port->socket[0], IPPROTO_IPV6,
98 				 IPV6_ADD_MEMBERSHIP, &mreqn, sizeof(mreqn));
99 	}
100 
101 	return 0;
102 }
103 
transport_udp_ipv4_open(struct net_if * iface,uint16_t port)104 static int transport_udp_ipv4_open(struct net_if *iface, uint16_t port)
105 {
106 	uint8_t tos;
107 	socklen_t length;
108 	int socket, ttl = 1;
109 	struct sockaddr_in addr = {
110 		.sin_family = AF_INET,
111 		.sin_addr = INADDR_ANY_INIT,
112 		.sin_port = htons(port),
113 	};
114 
115 	socket = transport_socket_open(iface, (struct sockaddr *)&addr);
116 	if (socket < 0) {
117 		return -1;
118 	}
119 
120 	if (zsock_setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))) {
121 		LOG_ERR("Failed to set ip multicast ttl socket option");
122 		goto error;
123 	}
124 
125 	if (zsock_getsockopt(socket, IPPROTO_IP, IP_TOS, &tos, &length)) {
126 		tos = 0;
127 	}
128 
129 	tos &= ~0xFC;
130 	tos |= CONFIG_PTP_DSCP_VALUE << 2;
131 	length = sizeof(tos);
132 
133 	if (zsock_setsockopt(socket, IPPROTO_IP, IP_TOS, &tos, length)) {
134 		LOG_WRN("Failed to set DSCP priority");
135 	}
136 
137 	return socket;
138 error:
139 	zsock_close(socket);
140 	return -1;
141 }
142 
transport_udp_ipv6_open(struct net_if * iface,uint16_t port)143 static int transport_udp_ipv6_open(struct net_if *iface, uint16_t port)
144 {
145 	uint8_t tclass;
146 	socklen_t length;
147 	int socket, hops = 1, feature_on = 1;
148 	struct sockaddr_in6 addr = {
149 		.sin6_family = AF_INET6,
150 		.sin6_addr = IN6ADDR_ANY_INIT,
151 		.sin6_port = htons(port)
152 	};
153 
154 	socket = transport_socket_open(iface, (struct sockaddr *)&addr);
155 	if (socket < 0) {
156 		return -1;
157 	}
158 
159 	if (zsock_setsockopt(socket,
160 			     IPPROTO_IPV6,
161 			     IPV6_RECVPKTINFO,
162 			     &feature_on,
163 			     sizeof(feature_on))) {
164 		LOG_ERR("Failed to set IPV6_RECVPKTINFO");
165 		goto error;
166 	}
167 
168 	if (zsock_setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops))) {
169 		LOG_ERR("Failed to set ip multicast hops socket option");
170 		goto error;
171 	}
172 
173 	if (zsock_getsockopt(socket, IPPROTO_IPV6, IPV6_TCLASS, &tclass, &length)) {
174 		tclass = 0;
175 	}
176 
177 	tclass &= ~0xFC;
178 	tclass |= CONFIG_PTP_DSCP_VALUE << 2;
179 	length = sizeof(tclass);
180 
181 	if (zsock_setsockopt(socket, IPPROTO_IPV6, IPV6_TCLASS, &tclass, length)) {
182 		LOG_WRN("Failed to set priority");
183 	}
184 
185 	return socket;
186 error:
187 	zsock_close(socket);
188 	return -1;
189 }
190 
transport_send(int socket,int port,void * buf,int length,struct sockaddr * addr)191 static int transport_send(int socket, int port, void *buf, int length, struct sockaddr *addr)
192 {
193 	struct sockaddr m_addr;
194 	socklen_t addrlen;
195 	int cnt;
196 
197 	if (!addr) {
198 		if (IS_ENABLED(CONFIG_PTP_UDP_IPv4_PROTOCOL)) {
199 			m_addr.sa_family = AF_INET;
200 			net_sin(&m_addr)->sin_port = htons(port);
201 			net_sin(&m_addr)->sin_addr.s_addr = mcast_addr.s_addr;
202 
203 		} else if (IS_ENABLED(CONFIG_PTP_UDP_IPv6_PROTOCOL)) {
204 			m_addr.sa_family = AF_INET6;
205 			net_sin6(&m_addr)->sin6_port = htons(port);
206 			memcpy(&net_sin6(&m_addr)->sin6_addr,
207 			       &mcast_addr,
208 			       sizeof(struct in6_addr));
209 		}
210 		addr = &m_addr;
211 	}
212 
213 	addrlen = IS_ENABLED(CONFIG_PTP_UDP_IPv4_PROTOCOL) ? sizeof(struct sockaddr_in) :
214 							     sizeof(struct sockaddr_in6);
215 	cnt = zsock_sendto(socket, buf, length, 0, addr, addrlen);
216 	if (cnt < 1) {
217 		LOG_ERR("Failed to send message");
218 		return -EFAULT;
219 	}
220 
221 	return cnt;
222 }
223 
ptp_transport_open(struct ptp_port * port)224 int ptp_transport_open(struct ptp_port *port)
225 {
226 	static const int socket_ports[] = {PTP_SOCKET_PORT_EVENT, PTP_SOCKET_PORT_GENERAL};
227 	int socket;
228 
229 	for (int i = 0; i < PTP_SOCKET_CNT; i++) {
230 		socket = IS_ENABLED(CONFIG_PTP_UDP_IPv4_PROTOCOL) ?
231 			transport_udp_ipv4_open(port->iface, socket_ports[i]) :
232 			transport_udp_ipv6_open(port->iface, socket_ports[i]);
233 
234 		if (socket == -1) {
235 			if (i == PTP_SOCKET_GENERAL) {
236 				zsock_close(port->socket[PTP_SOCKET_EVENT]);
237 				port->socket[PTP_SOCKET_EVENT] = -1;
238 			}
239 
240 			return -1;
241 		}
242 
243 		port->socket[i] = socket;
244 	}
245 
246 	return transport_join_multicast(port);
247 }
248 
ptp_transport_close(struct ptp_port * port)249 int ptp_transport_close(struct ptp_port *port)
250 {
251 	for (int i = 0; i < PTP_SOCKET_CNT; i++) {
252 
253 		if (port->socket[i] >= 0) {
254 			if (zsock_close(port->socket[i])) {
255 				LOG_ERR("Failed to close socket on PTP Port %d",
256 					port->port_ds.id.port_number);
257 				return -1;
258 			}
259 		}
260 
261 		port->socket[i] = -1;
262 	}
263 
264 	return 0;
265 }
266 
ptp_transport_send(struct ptp_port * port,struct ptp_msg * msg,enum ptp_socket idx)267 int ptp_transport_send(struct ptp_port *port, struct ptp_msg *msg, enum ptp_socket idx)
268 {
269 	__ASSERT(PTP_SOCKET_CNT <= idx, "Invalid socket index");
270 
271 	static const int socket_port[] = {PTP_SOCKET_PORT_EVENT, PTP_SOCKET_PORT_GENERAL};
272 	int length = ntohs(msg->header.msg_length);
273 
274 	return transport_send(port->socket[idx], socket_port[idx], msg, length, NULL);
275 }
276 
ptp_transport_sendto(struct ptp_port * port,struct ptp_msg * msg,enum ptp_socket idx)277 int ptp_transport_sendto(struct ptp_port *port, struct ptp_msg *msg, enum ptp_socket idx)
278 {
279 	__ASSERT(PTP_SOCKET_CNT <= idx, "Invalid socket index");
280 
281 	static const int socket_port[] = {PTP_SOCKET_PORT_EVENT, PTP_SOCKET_PORT_GENERAL};
282 	int length = ntohs(msg->header.msg_length);
283 
284 	return transport_send(port->socket[idx], socket_port[idx], msg, length, &msg->addr);
285 }
286 
ptp_transport_recv(struct ptp_port * port,struct ptp_msg * msg,enum ptp_socket idx)287 int ptp_transport_recv(struct ptp_port *port, struct ptp_msg *msg, enum ptp_socket idx)
288 {
289 	__ASSERT(PTP_SOCKET_CNT <= idx, "Invalid socket index");
290 
291 	int cnt = 0;
292 	uint8_t ctrl[CMSG_SPACE(sizeof(struct net_ptp_time))] = {0};
293 	struct cmsghdr *cmsg;
294 	struct msghdr msghdr = {0};
295 	struct iovec iov = {
296 		.iov_base = msg,
297 		.iov_len = sizeof(msg->mtu),
298 	};
299 
300 	msghdr.msg_iov = &iov;
301 	msghdr.msg_iovlen = 1;
302 	msghdr.msg_control = ctrl;
303 	msghdr.msg_controllen = sizeof(ctrl);
304 
305 	cnt = zsock_recvmsg(port->socket[idx], &msghdr, ZSOCK_MSG_DONTWAIT);
306 	if (cnt < 0) {
307 		LOG_ERR("Failed receive PTP message");
308 	}
309 
310 	for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
311 		if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMPING) {
312 			memcpy(&msg->timestamp.host, CMSG_DATA(cmsg), sizeof(struct net_ptp_time));
313 		}
314 	}
315 
316 	return cnt;
317 }
318 
ptp_transport_protocol_addr(struct ptp_port * port,uint8_t * addr)319 int ptp_transport_protocol_addr(struct ptp_port *port, uint8_t *addr)
320 {
321 	__ASSERT_NO_MSG(addr);
322 
323 	int length = 0;
324 
325 	if (IS_ENABLED(CONFIG_PTP_UDP_IPv4_PROTOCOL)) {
326 		struct in_addr *ip = net_if_ipv4_get_global_addr(port->iface, NET_ADDR_PREFERRED);
327 
328 		length = NET_IPV4_ADDR_SIZE;
329 		*addr = ip->s_addr;
330 	} else if (IS_ENABLED(CONFIG_PTP_UDP_IPv6_PROTOCOL)) {
331 		struct in6_addr *ip = net_if_ipv6_get_global_addr(NET_ADDR_PREFERRED, &port->iface);
332 
333 		length = NET_IPV6_ADDR_SIZE;
334 		memcpy(addr, ip, length);
335 	}
336 
337 	return length;
338 }
339 
ptp_transport_physical_addr(struct ptp_port * port)340 struct net_linkaddr *ptp_transport_physical_addr(struct ptp_port *port)
341 {
342 	return net_if_get_link_addr(port->iface);
343 }
344