flexPTP 1.0
An IEEE 1588 PTP implementation designed for microcontrollers
Loading...
Searching...
No Matches
nsd_linux.c
Go to the documentation of this file.
1#include "../../network_stack_driver.h"
2
3#include "../../ptp_defs.h"
4#include "../../task_ptp.h"
5
6#include <arpa/inet.h>
7#include <asm-generic/errno-base.h>
8#include <asm/socket.h>
9#include <fcntl.h>
10#include <linux/ethtool.h>
11#include <linux/net_tstamp.h>
12#include <linux/sockios.h>
13#include <net/if.h>
14#include <netinet/in.h>
15#include <stdio.h>
16#include <string.h>
17#include <sys/ioctl.h>
18#include <sys/socket.h>
19#include <unistd.h>
20#include <inttypes.h>
21
22#include <features.h>
23#include <asm-generic/unistd.h>
24#include <bits/time.h>
25
26#include <linux/if_packet.h>
27#include <netinet/ether.h>
28#include <poll.h>
29#include <pthread.h>
30#include <sys/socket.h>
31#include <sys/timex.h>
32
33#define LINUX_NSD_TS_DEBUG (0) // timestamp debugging
34#define LINUX_NSD_TX_ENQUEUE_DEBUG (0) // transmit enqueue debugging
35
36// initialize connection blocks to invalid states
37static int event_fd = -1;
38static int general_fd = -1;
39
40// store current settings
41static PtpTransportType TP = -1;
43
44// interface data
45static uint16_t if_idx; // interface index
46static char if_name[IFNAMSIZ]; // name of the interface
47static uint8_t if_hwaddr[IFHWADDRLEN]; // hardware address of the interface
48static struct sockaddr_in if_ipaddr; // IP-address of the interface
49
50// hardware clock data
51#define PHY_FILE_NAME_SIZE (16)
52static uint16_t phc_index; // index of the PHC
53static char phc_file_name[PHY_FILE_NAME_SIZE]; // PHC device file name
54static int phc_fd; // PHC file descriptor
55static clockid_t phc_clkid; // PHC clock id
56
57// transception management
58static int notif_q[2]; // notification queue
59static int matching_q[2]; // message pointer queue
60static pthread_t transceiver_thread; // thread managing transmission and reception
61static void *nsd_thread(void *arg); // thread function
62
63#define PRINT_HWADDR(a) MSG("%02X:%02X:%02X:%02X:%02X:%02X", a[0], a[1], a[2], a[3], a[4], a[5]);
64
65#define NOTIF_QUIT_TRANSCEIVER_THREAD 'Q'
66
67static void post_notification(char c) {
68 write(notif_q[1], &c, 1);
69}
70
71/* FD <-> CLOCKID conversions (man 2 clock_getres, 'Dynamic clocks' section) */
72#define CLOCKFD 3
73#define FD_TO_CLOCKID(fd) ((clockid_t)((((unsigned int)~fd) << 3) | CLOCKFD))
74#define CLOCKID_TO_FD(clk) ((unsigned int)~((clk) >> 3))
75
76bool linux_nsd_preinit(const char *ifn) {
77 bool init_ok = false;
78
79 // copy interface name
80 strncpy(if_name, ifn, IFNAMSIZ - 1);
81 if_name[IFNAMSIZ - 1] = '\0';
82
83 // create dummy socket
84 int fd = socket(PF_INET, SOCK_DGRAM, 0);
85 if (fd < 0) {
86 MSG("Could not create a dummy socket to retrieve interface data!\n");
87 return false;
88 }
89
90 int err;
91
92 // retrieve the network interface index
93 // man 7 netdevice
94 struct ifreq ifr;
95 memset(&ifr, 0, sizeof(ifr));
96 strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
97 err = ioctl(fd, SIOCGIFINDEX, &ifr);
98 if (err < 0) {
99 MSG("Could not get interface index!\n");
100 goto cleanup;
101 }
102 if_idx = ifr.ifr_ifindex;
103
104 // retrieve the hardware address of the interface
105 // man 7 netdevice
106 memset(&ifr, 0, sizeof(ifr));
107 strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
108 err = ioctl(fd, SIOCGIFHWADDR, &ifr);
109 if (err < 0) {
110 MSG("Failed to retrieve the hardware address!\n");
111 goto cleanup;
112 }
113 memcpy(if_hwaddr, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
114
115 // retrieve the IP address of the interface
116 // man 7 netdevice
117 memset(&ifr, 0, sizeof(ifr));
118 ifr.ifr_addr.sa_family = AF_INET;
119 strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
120 err = ioctl(fd, SIOCGIFADDR, &ifr);
121 if (err < 0) {
122 MSG("Failed to retrieve the interface IP address!\n");
123 goto cleanup;
124 }
125 memcpy(&if_ipaddr, &ifr.ifr_addr, sizeof(struct sockaddr_in));
126
127 // print collected information
128 MSG("Network Interface information\n");
129 MSG("-- Interface: " PTP_COLOR_YELLOW "%s\n" PTP_COLOR_RESET, if_name);
130 MSG(" Hardware address: " PTP_COLOR_CYAN);
132 MSG("\n");
133 MSG(PTP_COLOR_RESET);
134 MSG(" IP-address: " PTP_COLOR_CYAN "%s\n" PTP_COLOR_RESET, inet_ntoa(if_ipaddr.sin_addr));
135
136 // check the hardware timestamp support
137 // https://docs.kernel.org/networking/ethtool-netlink.html#tsinfo-get
138 struct ethtool_ts_info tsi = {.cmd = ETHTOOL_GET_TS_INFO};
139 memset(&ifr, 0, sizeof(ifr));
140 strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1);
141 ifr.ifr_data = (caddr_t)&tsi;
142 err = ioctl(fd, SIOCETHTOOL, &ifr);
143 if (err < 0) {
144 MSG("Failed to query the interface timestamp capabilities!\n");
145 goto cleanup;
146 }
147
148 // print timestamp information
149 MSG(" Hardware timestamping: ");
150 if ((tsi.so_timestamping & SOF_TIMESTAMPING_TX_HARDWARE) && (tsi.so_timestamping & SOF_TIMESTAMPING_RX_HARDWARE)) {
151 phc_index = tsi.phc_index;
154
156 MSG(" PHC index: " PTP_COLOR_CYAN "%u\n" PTP_COLOR_RESET, phc_index);
157 MSG(" -- corresponding file: " PTP_COLOR_CYAN "%s\n" PTP_COLOR_RESET, phc_file_name);
158 } else {
159 MSG(PTP_COLOR_RED "MISSING\n" PTP_COLOR_RESET);
160 goto cleanup;
161 }
162 MSG("---------------\n\n");
163
164 // open PHC
165 phc_fd = open(phc_file_name, O_RDWR);
166 if (phc_fd < 0) {
167 MSG("Failed to open PHC file!\n");
168 goto cleanup;
169 }
171
172 struct timespec ts;
173 if (clock_gettime(phc_clkid, &ts) < 0) {
174 MSG("Failed to access the PHC time!\n");
175 goto cleanup;
176 }
177
178 // create the notification queue
179 if (pipe(notif_q) < 0) {
180 MSG("Failed to create notification queue!\n");
181 goto cleanup;
182 }
183
184 // create message pointer queue
185 if (pipe(matching_q) < 0) {
186 MSG("Failed to create buffer matching pointer queue!\n");
187 goto cleanup;
188 }
189
190 // clear thread handle
192
193 // initialization done
194 init_ok = true;
195 return init_ok;
196
197cleanup:
198 if (fd > 0) {
199 close(fd);
200 }
201 if (phc_fd > 0) {
202 close(phc_fd);
203 }
204 return init_ok;
205}
206
208 if (phc_fd > 0) {
209 close(phc_fd);
210 phc_fd = 0;
211 }
212}
213
214static void socket_join_igmp(int fd) {
215 // fill in the multicast assignment request
216 struct ip_mreq mreq;
217 if (DM == PTP_DM_E2E) {
218 mreq.imr_multiaddr.s_addr = PTP_IGMP_PRIMARY;
219 } else if (DM == PTP_DM_P2P) {
220 mreq.imr_multiaddr.s_addr = PTP_IGMP_PEER_DELAY;
221 }
222 mreq.imr_interface = if_ipaddr.sin_addr;
223
224 // join the IGMP group
225 // man 7 ip
226 int err = setsockopt(event_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
227 if (err < 0) {
228 // MSG("Could not join the required network group!\n");
229 }
230}
231
232void ptp_nsd_igmp_join_leave(bool join) {
233 // only join IGMP if Transport Type is IP
234 if ((TP == PTP_TP_IPv4) && join) {
235 if (event_fd > 0) {
237 }
238 if (general_fd > 0) {
240 }
241 }
242
243 // don't have to explicitly leave the IGMP group
244}
245
246static int open_udp_socket(PtpDelayMechanism dm, uint16_t port, const char *hint) {
247 // prepare socket address
248 struct sockaddr_in addr;
249 memset(&addr, 0, sizeof(addr));
250 addr.sin_family = PF_INET;
251 addr.sin_addr.s_addr = (dm == PTP_DM_E2E) ? PTP_IGMP_PRIMARY : PTP_IGMP_PEER_DELAY;
252
253 // create socket
254 // man 2 socket
255 int sfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
256 if (sfd < 0) {
257 MSG("Could not open the %s socket!\n", hint);
258 return -1;
259 }
260
261 // enable the reuseaddr option
262 // man 3 setsockopt
263 int optval = 1;
264 int err = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
265 if (err < 0) {
266 MSG("Could not set the %s socket REUSEADDR option!\n", hint);
267 goto cleanup;
268 }
269
270 // assign the multicast transmit interface with the socket
271 // man 7 ip
272 err = setsockopt(sfd, IPPROTO_IP, IP_MULTICAST_IF, &if_ipaddr.sin_addr, sizeof(struct in_addr));
273 if (err < 0) {
274 MSG("Could not set the %s socket IP_MULTICAST_IF option!\n", hint);
275 goto cleanup;
276 }
277
278 // bind the socket
279 // man 2 bind
280 addr.sin_port = htons(port);
281 err = bind(sfd, (struct sockaddr *)&addr, sizeof(addr));
282 if (err < 0) {
283 MSG("Could not bind the %s socket!\n", hint);
284 goto cleanup;
285 }
286
287 // normal return
288 return sfd;
289
290cleanup:
291 close(sfd);
292 return -1;
293}
294
295static int open_raw_socket(PtpDelayMechanism dm, bool bind_socket, const char *hint) {
296 const uint8_t *ethaddr = (dm == PTP_DM_E2E) ? PTP_ETHERNET_PRIMARY : PTP_ETHERNET_PEER_DELAY;
297
298 // create socket
299 // SOCK_DGRAM: use the kernel features to fill in the Ethernet header
300 int sfd = socket(AF_PACKET, SOCK_DGRAM, htons(PTP_ETHERTYPE));
301 if (sfd < 0) {
302 MSG("Could not open the %s socket!\n", hint);
303 return -1;
304 }
305
306 // setup address
307 // man 7 packet
308 struct sockaddr_ll addr;
309 memset(&addr, 0, sizeof(addr));
310 addr.sll_ifindex = if_idx;
311 addr.sll_halen = ETH_ALEN;
312 addr.sll_protocol = htons(PTP_ETHERTYPE);
313 addr.sll_family = AF_PACKET;
314 addr.sll_pkttype = PACKET_MULTICAST;
315 memcpy(addr.sll_addr, ethaddr, ETH_ALEN);
316
317 // bind socket if requested
318 // man 2 bind
319 int err;
320 if (bind_socket) {
321 err = bind(sfd, (struct sockaddr *)&addr, sizeof(addr));
322 if (err < 0) {
323 MSG("Could not bind the %s socket!\n", hint);
324 }
325 }
326
327 // assign the socket the multicast membership
328 // man 6 packet
329 struct packet_mreq mreq;
330 mreq.mr_ifindex = if_idx;
331 mreq.mr_type = PACKET_MR_MULTICAST;
332 mreq.mr_alen = ETH_ALEN;
333 memcpy(mreq.mr_address, ethaddr, ETH_ALEN);
334
335 err = setsockopt(sfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
336 if (err < 0) {
337 MSG("Could not set the %s socket ADD_MEMBERSHIP option!\n", hint);
338 }
339
340 return sfd;
341}
342
343static void enable_timestamping(int sfd) {
344 // enable timestamping on the socket
345 // https://www.kernel.org/doc/html/latest/networking/timestamping.html#scm-timestamping-records
346 int optval = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_TX_HARDWARE;
347 int err = setsockopt(sfd, SOL_SOCKET, SO_TIMESTAMPING, &optval, sizeof(optval));
348 if (err < 0) {
349 MSG("Failed to enable timestamping\n");
350 }
351
352 // enable timestamping in the hardware
353 struct ifreq ifreq;
354 struct hwtstamp_config cfg;
355 memset(&ifreq, 0, sizeof(ifreq));
356 memset(&cfg, 0, sizeof(cfg));
357 strncpy(ifreq.ifr_name, if_name, IFNAMSIZ - 1);
358 ifreq.ifr_data = (void *)&cfg;
359
360 // get current timestamping settings
361 err = ioctl(sfd, SIOCGHWTSTAMP, &ifreq);
362 if (err < 0) {
363 MSG("Failed to get timestamping settings.\n");
364 return;
365 }
366
367 // turn on TX and RX timestamping
368 // https://www.kernel.org/doc/html/latest/networking/timestamping.html#hardware-timestamping-configuration-ethtool-msg-tsconfig-set-get
369 cfg.flags = 0;
370 cfg.tx_type = HWTSTAMP_TX_ON;
371 cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
372 err = ioctl(sfd, SIOCSHWTSTAMP, &ifreq);
373 if (err < 0) {
374 MSG("Failed to set timestamping settings.\n");
375 }
376
377 // enable TX timestamp communication through the socket error queue
378 // man 7 socket
379 optval = 1;
380 err = setsockopt(sfd, SOL_SOCKET, SO_SELECT_ERR_QUEUE, &optval, sizeof(optval));
381 if (err < 0) {
382 MSG("Could not enable TX timestamp communication through the error queue!\n");
383 }
384}
385
386#define NAME_BUF_SIZE (256)
388#define MSG_BUF_SIZE (1600)
390#define CTRL_BUF_SIZE (256)
392
393static void *nsd_thread(void *arg) {
394 bool run = true;
395 while (run) {
396 // populate the poll list
397 struct pollfd pfd[] = {
398 {.fd = notif_q[0], .events = POLLIN},
399 {.fd = event_fd, .events = POLLIN | POLLPRI},
400 {.fd = general_fd, .events = POLLIN},
401 };
402
403 // in IEEE 802.3 mode only the first two slots are used
404 int n = (TP == PTP_TP_IPv4) ? 3 : 2;
405
406 // make the poll
407 int pret = poll(pfd, n, -1);
408 if (pret > 0) {
409 // notifications
410 if (pfd[0].revents & POLLIN) {
411 char c;
412 read(notif_q[0], &c, sizeof(char));
414 run = false;
415 continue;
416 }
417 }
418
419 // something had happened on the event message socket
420 if (pfd[1].revents != 0) {
421
422 // prepare for message reception
423 struct iovec iov = {msg_buf, MSG_BUF_SIZE};
424 struct msghdr msg;
425
426 memset(&msg, 0, sizeof(msg));
427 memset(msg_buf, 0, sizeof(msg_buf));
428
429 msg.msg_name = name_buf;
430 msg.msg_namelen = NAME_BUF_SIZE;
431 msg.msg_iov = &iov;
432 msg.msg_iovlen = 1;
433 msg.msg_control = rx_ctrl_buf;
434 msg.msg_controllen = CTRL_BUF_SIZE;
435
436 // event message TRANSMISSION timestamp feedback
437 // https://www.kernel.org/doc/html/latest/networking/timestamping.html#scm-timestamping-records
438 if (pfd[1].revents & POLLPRI) {
439 ssize_t size = recvmsg(event_fd, &msg, MSG_ERRQUEUE); // get transmit timestamps from the error queue
440 struct cmsghdr *cm; // iterate over the chain of control messages
441 for (cm = CMSG_FIRSTHDR(&msg); cm != NULL; cm = CMSG_NXTHDR(&msg, cm)) {
442 int level = cm->cmsg_level;
443 int type = cm->cmsg_type;
444 if ((level == SOL_SOCKET) && (type == SO_TIMESTAMPING)) {
445 struct timespec *ts = (struct timespec *)CMSG_DATA(cm); // get data from the timestamp control message
446 uint32_t uid = 0;
447 read(matching_q[0], &uid, sizeof(uint32_t));
448
449 struct timespec now;
450 clock_gettime(CLOCK_REALTIME, &now);
451 CLILOG(LINUX_NSD_TS_DEBUG, "[%lu.%09lu] TX TS: (%u) %lu.%09lu\n", now.tv_sec, now.tv_nsec, uid, ts[2].tv_sec, ts[2].tv_nsec);
452
453 // invoke the transmit timestamp callback, the hardware timestamp always comes in ts[2]
454 ptp_transmit_timestamp_cb(uid, ts[2].tv_sec, ts[2].tv_nsec);
455 }
456 }
457 }
458
459 // event message RECEPTION
460 if (pfd[1].revents & POLLIN) {
461 ssize_t size = recvmsg(event_fd, &msg, 0);
462 struct cmsghdr *cm;
463 struct timespec ts;
464 memset(&ts, 0, sizeof(ts));
465 bool ts_found = false;
466 for (cm = CMSG_FIRSTHDR(&msg); cm != NULL; cm = CMSG_NXTHDR(&msg, cm)) {
467 int level = cm->cmsg_level;
468 int type = cm->cmsg_type;
469 if ((level == SOL_SOCKET) && (type == SO_TIMESTAMPING)) {
470 struct timespec *tsa = (struct timespec *)CMSG_DATA(cm); // get pointer to the timestamps
471 ts = tsa[2]; // extract the hardware timestamp
472 ts_found = true; // indicate that timestamp was found
473 CLILOG(LINUX_NSD_TS_DEBUG, "RX TS: %lu.%09lu\n", ts.tv_sec, ts.tv_nsec);
474 }
475 }
476
477 // forward only event messages over IPv4 and ALL messages over Ethernet
478 if (((TP == PTP_TP_IPv4) && (ts_found)) || (TP == PTP_TP_802_3)) {
479 ptp_receive_enqueue(msg_buf, size, ts.tv_sec, ts.tv_nsec, TP);
480 }
481 }
482 }
483
484 // general message reception (in IPv4 mode)
485 if (TP == PTP_TP_IPv4) {
486 if (pfd[2].revents & POLLIN) {
487 ssize_t size = recv(general_fd, msg_buf, MSG_BUF_SIZE, 0);
488 if (size > 0) {
489 ptp_receive_enqueue(msg_buf, size, 0, 0, TP);
490 }
491 }
492 }
493 }
494 }
495
496 return NULL;
497}
498
500 // leave current IGMP group if applicable
502
503 // first, close all open connection blocks (zero CBDs won't cause trouble)
504 if (transceiver_thread != 0) {
506 pthread_join(transceiver_thread, NULL);
508 }
509 if (event_fd > 0) {
510 close(event_fd);
511 event_fd = -1;
512 }
513 if (general_fd > 0) {
514 close(general_fd);
515 general_fd = -1;
516 }
517
518 // calling either parameter with -1 just closes connections
519 if ((tp == -1) || (dm == -1)) {
520 // message transmission and reception is turned off
521 TP = -1;
522 DM = -1;
523 return;
524 }
525
526 // open event and general connections
527 if (tp == PTP_TP_IPv4) {
530 } else if (tp == PTP_TP_802_3) {
531 event_fd = open_raw_socket(dm, true, "EVENT");
532 general_fd = open_raw_socket(dm, false, "GENERAL");
533 }
534
535 // enable timestamping on the event socket
537
538 // create the transceiver thread
540 if (pthread_create(&transceiver_thread, NULL, nsd_thread, NULL) != 0) {
541 MSG("Failed to create the transceiver thread!\n");
542 }
543
544 // store configuration
545 TP = tp;
546 DM = dm;
547
548 // join new IGMP group
550}
551
552void ptp_nsd_transmit_msg(RawPtpMessage *pMsg, uint32_t uid) {
553 if (pMsg == NULL) {
554 return;
555 }
556
557 // indicates if the transmission was successful
558 bool send_ok = false;
559
560 // get the message class
561 PtpMessageClass mc = pMsg->tx_mc;
562
563 // select connection by message type
564 int sfd = (mc == PTP_MC_EVENT) ? event_fd : general_fd;
565
566 // narrow down by transport type
567 if (TP == PTP_TP_IPv4) {
568 // configure the address
569 struct sockaddr_in addr;
570 memset(&addr, 0, sizeof(addr));
571 addr.sin_family = PF_INET;
572 addr.sin_addr.s_addr = (DM == PTP_DM_E2E) ? PTP_IGMP_PRIMARY : PTP_IGMP_PEER_DELAY; // select destination IP-address by delmech.
573 addr.sin_port = htons((mc == PTP_MC_EVENT) ? PTP_PORT_EVENT : PTP_PORT_GENERAL); // select port by message class
574
575 // send packet
576 if (sendto(sfd, pMsg->data, pMsg->size, 0, (struct sockaddr *)&addr, sizeof(addr)) == pMsg->size) {
577 send_ok = true;
578 }
579 } else if (TP == PTP_TP_802_3) {
580 // destination address
581 const uint8_t *ethaddr = (DM == PTP_DM_E2E) ? PTP_ETHERNET_PRIMARY : PTP_ETHERNET_PEER_DELAY; // select destination address by delmech.
582
583 // prepare address object
584 struct sockaddr_ll addr;
585 memset(&addr, 0, sizeof(addr));
586 addr.sll_ifindex = if_idx;
587 addr.sll_halen = ETH_ALEN;
588 addr.sll_protocol = htons(PTP_ETHERTYPE);
589 memcpy(addr.sll_addr, ethaddr, ETH_ALEN);
590
591 if (sendto(sfd, pMsg->data, pMsg->size, 0, (struct sockaddr *)&addr, sizeof(addr)) == pMsg->size) {
592 send_ok = true;
593 };
594 }
595
596 // send message UID to the queue or invoke the TX callback
597 if (send_ok) {
598 struct timespec now;
599 clock_gettime(CLOCK_REALTIME, &now);
600 CLILOG(LINUX_NSD_TX_ENQUEUE_DEBUG, "[%lu.%09lu] TX enqueue! %u\n", now.tv_sec, now.tv_nsec, uid);
601 if (mc == PTP_MC_EVENT) {
602 write(matching_q[1], &uid, sizeof(uint32_t));
603 } else if (mc == PTP_MC_GENERAL) {
604 ptp_transmit_timestamp_cb(uid, 0, 0);
605 }
606 }
607}
608
610 memcpy(hwa, if_hwaddr, IFHWADDRLEN);
611}
612
613// ------------------------
614
615/* man 2 clock_adjtime (ADJ_FREQUENCY) */
616#define PPB_TO_TUNING_SCALER (((double)(1 << 16)) / 1000.0)
617
618void linux_adjust_clock(double tuning_ppb) {
619 struct timex tx;
620 memset(&tx, 0, sizeof(struct timex));
621 if (clock_adjtime(phc_clkid, &tx) < 0) {
622 MSG("Failed to retrieve PHC tuning!\n");
623 }
624 memset(&tx, 0, sizeof(struct timex));
625 tx.modes = ADJ_FREQUENCY;
626 tx.freq = (__syscall_slong_t)(tuning_ppb * PPB_TO_TUNING_SCALER);
627 if (clock_adjtime(phc_clkid, &tx) != 0) {
628 MSG("Failed to adjust PHC frequency!\n");
629 }
630}
631
632void linux_set_time(uint32_t seconds, uint32_t nanoseconds) {
633 struct timespec ts = {.tv_sec = seconds, .tv_nsec = nanoseconds};
634 if (clock_settime(phc_clkid, &ts) < 0) {
635 MSG("Failed to set the PHC time!\n");
636 }
637}
638
640 struct timespec ts;
641 if (clock_gettime(phc_clkid, &ts) < 0) {
642 MSG("Failed to get the PHC time!\n");
643 }
644
645 pTime->sec = ts.tv_sec;
646 pTime->nanosec = ts.tv_nsec;
647}
#define CLILOG(en,...)
#define FLEXPTP_SNPRINTF(...)
static struct sockaddr_in if_ipaddr
Definition: nsd_linux.c:48
void linux_nsd_cleanup(void)
Definition: nsd_linux.c:207
void ptp_nsd_transmit_msg(RawPtpMessage *pMsg, uint32_t uid)
Definition: nsd_linux.c:552
#define NAME_BUF_SIZE
Definition: nsd_linux.c:386
static void enable_timestamping(int sfd)
Definition: nsd_linux.c:343
static int notif_q[2]
Definition: nsd_linux.c:58
static uint16_t if_idx
Definition: nsd_linux.c:45
static PtpDelayMechanism DM
Definition: nsd_linux.c:42
void ptp_nsd_igmp_join_leave(bool join)
Definition: nsd_linux.c:232
void ptp_nsd_init(PtpTransportType tp, PtpDelayMechanism dm)
Definition: nsd_linux.c:499
#define PPB_TO_TUNING_SCALER
Definition: nsd_linux.c:616
void linux_get_time(TimestampU *pTime)
Definition: nsd_linux.c:639
void linux_set_time(uint32_t seconds, uint32_t nanoseconds)
Definition: nsd_linux.c:632
static clockid_t phc_clkid
Definition: nsd_linux.c:55
#define LINUX_NSD_TS_DEBUG
Definition: nsd_linux.c:33
static int open_udp_socket(PtpDelayMechanism dm, uint16_t port, const char *hint)
Definition: nsd_linux.c:246
void linux_adjust_clock(double tuning_ppb)
Definition: nsd_linux.c:618
#define PRINT_HWADDR(a)
Definition: nsd_linux.c:63
static void socket_join_igmp(int fd)
Definition: nsd_linux.c:214
bool linux_nsd_preinit(const char *ifn)
Definition: nsd_linux.c:76
static int open_raw_socket(PtpDelayMechanism dm, bool bind_socket, const char *hint)
Definition: nsd_linux.c:295
static char msg_buf[(1600)]
Definition: nsd_linux.c:389
#define CTRL_BUF_SIZE
Definition: nsd_linux.c:390
void ptp_nsd_get_interface_address(uint8_t *hwa)
Definition: nsd_linux.c:609
static char name_buf[(256)]
Definition: nsd_linux.c:387
#define MSG_BUF_SIZE
Definition: nsd_linux.c:388
static char if_name[IFNAMSIZ]
Definition: nsd_linux.c:46
#define NOTIF_QUIT_TRANSCEIVER_THREAD
Definition: nsd_linux.c:65
static uint8_t if_hwaddr[IFHWADDRLEN]
Definition: nsd_linux.c:47
static int event_fd
Definition: nsd_linux.c:37
static int matching_q[2]
Definition: nsd_linux.c:59
static PtpTransportType TP
Definition: nsd_linux.c:41
static int phc_fd
Definition: nsd_linux.c:54
static int general_fd
Definition: nsd_linux.c:38
static uint16_t phc_index
Definition: nsd_linux.c:52
static pthread_t transceiver_thread
Definition: nsd_linux.c:60
static char rx_ctrl_buf[(256)]
Definition: nsd_linux.c:391
#define FD_TO_CLOCKID(fd)
Definition: nsd_linux.c:73
static void post_notification(char c)
Definition: nsd_linux.c:67
#define PHY_FILE_NAME_SIZE
Definition: nsd_linux.c:51
static char phc_file_name[(16)]
Definition: nsd_linux.c:53
#define LINUX_NSD_TX_ENQUEUE_DEBUG
Definition: nsd_linux.c:34
static void * nsd_thread(void *arg)
Definition: nsd_linux.c:393
const uint8_t PTP_ETHERNET_PEER_DELAY[6]
PTP's L2 Peer_Delay Ethernet address.
Definition: ptp_defs.c:4
const uint8_t PTP_ETHERNET_PRIMARY[6]
PTP's L2 Primary Ethernet address.
Definition: ptp_defs.c:3
const ip_addr_t PTP_IGMP_PRIMARY
Primary IGMP address.
#define PTP_PORT_EVENT
PTP event message port.
Definition: ptp_defs.h:45
#define PTP_COLOR_GREEN
Green.
Definition: ptp_defs.h:206
#define PTP_ETHERTYPE
PTP EtherType.
Definition: ptp_defs.h:37
#define PTP_COLOR_CYAN
Cyan.
Definition: ptp_defs.h:213
#define PTP_PORT_GENERAL
PTP general message port.
Definition: ptp_defs.h:46
#define PTP_COLOR_RESET
Reset colors.
Definition: ptp_defs.h:214
#define PTP_COLOR_RED
< Define this to override PTP_COLOR_* macros
Definition: ptp_defs.h:204
#define PTP_COLOR_YELLOW
Yellow.
Definition: ptp_defs.h:208
const ip_addr_t PTP_IGMP_PEER_DELAY
Peer_Delay IGMP address.
PtpTransportType
PTP transport type enumeration.
Definition: ptp_types.h:136
@ PTP_TP_IPv4
IPv4 Transport Type.
Definition: ptp_types.h:137
@ PTP_TP_802_3
Ethernet Transport Type.
Definition: ptp_types.h:138
PtpMessageClass
Enumeration for different PTP message classes.
Definition: ptp_types.h:160
@ PTP_MC_EVENT
Event Message Class.
Definition: ptp_types.h:161
@ PTP_MC_GENERAL
General Message Class.
Definition: ptp_types.h:162
PtpDelayMechanism
PTP Delay mechanism enumeration.
Definition: ptp_types.h:144
@ PTP_DM_E2E
End-to-End Delay Mechanism.
Definition: ptp_types.h:145
@ PTP_DM_P2P
Peer-to-Peer Delay Mechanism.
Definition: ptp_types.h:146
PtpMessageClass tx_mc
transmit message class
Definition: ptp_types.h:195
uint32_t size
Packet size.
Definition: ptp_types.h:188
uint8_t data[(128)]
raw packet data
Definition: ptp_types.h:198
Timestamp (unsigned)
Definition: timeutils.h:24
uint32_t nanosec
nanoseconds
Definition: timeutils.h:26
uint64_t sec
seconds
Definition: timeutils.h:25
void ptp_receive_enqueue(const void *pPayload, uint32_t len, uint32_t ts_sec, uint32_t ts_ns, int tp)
Definition: task_ptp.c:457
void ptp_transmit_timestamp_cb(uint32_t uid, uint32_t seconds, uint32_t nanoseconds)
Definition: task_ptp.c:537