1 /*-
2 * Copyright (c) 2014 Wojciech Owczarek,
3 * George V. Neville-Neil
4 * Copyright (c) 2012-2013 George V. Neville-Neil,
5 * Wojciech Owczarek.
6 * Copyright (c) 2011-2012 George V. Neville-Neil,
7 * Steven Kreuzer,
8 * Martin Burnicki,
9 * Jan Breuer,
10 * Gael Mace,
11 * Alexandre Van Kempen,
12 * Inaqui Delgado,
13 * Rick Ratzel,
14 * National Instruments.
15 * Copyright (c) 2009-2010 George V. Neville-Neil,
16 * Steven Kreuzer,
17 * Martin Burnicki,
18 * Jan Breuer,
19 * Gael Mace,
20 * Alexandre Van Kempen
21 *
22 * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
23 *
24 * All Rights Reserved
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions are
28 * met:
29 * 1. Redistributions of source code must retain the above copyright notice,
30 * this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
36 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
37 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
43 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
44 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
45 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 */
47
48 /**
49 * @file net.c
50 * @date Tue Jul 20 16:17:49 2010
51 *
52 * @brief Functions to interact with the network sockets and NIC driver.
53 *
54 *
55 */
56
57 #include "../ptpd.h"
58
59 #ifdef PTPD_PCAP
60 #ifdef HAVE_PCAP_PCAP_H
61 #include <pcap/pcap.h>
62 #else /* !HAVE_PCAP_PCAP_H */
63 /* Cases like RHEL5 and others where only pcap.h exists */
64 #ifdef HAVE_PCAP_H
65 #include <pcap.h>
66 #endif /* HAVE_PCAP_H */
67 #endif
68 #define PCAP_TIMEOUT 1 /* expressed in milliseconds */
69 #endif
70
71 #if defined PTPD_SNMP
72 #include <net-snmp/net-snmp-config.h>
73 #include <net-snmp/net-snmp-includes.h>
74 #include <net-snmp/agent/net-snmp-agent-includes.h>
75 #endif
76
77 /* choose kernel-level nanoseconds or microseconds resolution on the client-side */
78 #if !defined(SO_TIMESTAMPING) && !defined(SO_TIMESTAMPNS) && !defined(SO_TIMESTAMP) && !defined(SO_BINTIME)
79 #error No kernel-level support for packet timestamping detected!
80 #endif
81
82 #ifdef SO_TIMESTAMPING
83 #include <linux/net_tstamp.h>
84 #include <linux/sockios.h>
85 #include <linux/ethtool.h>
86 #endif /* SO_TIMESTAMPING */
87
88 /**
89 * shutdown the IPv4 multicast for specific address
90 *
91 * @param netPath
92 * @param multicastAddr
93 *
94 * @return TRUE if successful
95 */
96 static Boolean
97 netShutdownMulticastIPv4(NetPath * netPath, Integer32 multicastAddr)
98 {
99 struct ip_mreq imr;
100
101 /* Close General Multicast */
102 imr.imr_multiaddr.s_addr = multicastAddr;
103 imr.imr_interface.s_addr = netPath->interfaceAddr.s_addr;
104
105 setsockopt(netPath->eventSock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
106 &imr, sizeof(struct ip_mreq));
107 setsockopt(netPath->generalSock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
108 &imr, sizeof(struct ip_mreq));
109
110 return TRUE;
111 }
112
113 /**
114 * shutdown the multicast (both General and Peer)
115 *
116 * @param netPath
117 *
118 * @return TRUE if successful
119 */
120 static Boolean
121 netShutdownMulticast(NetPath * netPath)
122 {
123 /* Close General Multicast */
124 netShutdownMulticastIPv4(netPath, netPath->multicastAddr);
125 netPath->multicastAddr = 0;
126
127 /* Close Peer Multicast */
128 netShutdownMulticastIPv4(netPath, netPath->peerMulticastAddr);
129 netPath->peerMulticastAddr = 0;
130
131 return TRUE;
132 }
133
134 /*
135 * For future use: Check if IPv4 address is multiast -
136 * If last 4 bits of an address are 0xE (1110), it's multicast
137 */
138 /*
139 static Boolean
140 isIpMulticast(struct in_addr in)
141 {
142 if((ntohl(in.s_addr) >> 28) == 0x0E )
143 return TRUE;
144 return FALSE;
145 }
146 */
147
148 /* shut down the UDP stuff */
149 Boolean
150 netShutdown(NetPath * netPath)
151 {
152 netShutdownMulticast(netPath);
153
154 netPath->unicastAddr = 0;
155
156 /* Close sockets */
157 if (netPath->eventSock >= 0)
158 close(netPath->eventSock);
159 netPath->eventSock = -1;
160
161 if (netPath->generalSock >= 0)
162 close(netPath->generalSock);
163 netPath->generalSock = -1;
164
165 #ifdef PTPD_PCAP
166 if (netPath->pcapEvent != NULL) {
167 pcap_close(netPath->pcapEvent);
168 netPath->pcapEventSock = -1;
169 }
170 if (netPath->pcapGeneral != NULL) {
171 pcap_close(netPath->pcapGeneral);
172 netPath->pcapGeneralSock = -1;
173 }
174 #endif
175
176 freeIpv4AccessList(&netPath->timingAcl);
177 freeIpv4AccessList(&netPath->managementAcl);
178
179 return TRUE;
180 }
181
182 /* Check if interface ifaceName exists. Return 1 on success, 0 when interface doesn't exists, -1 on failure.
183 */
184
185 static int
186 interfaceExists(char* ifaceName)
187 {
188
189 int ret;
190 struct ifaddrs *ifaddr, *ifa;
191
192 if(!strlen(ifaceName)) {
193 DBG("interfaceExists called for an empty interface!");
194 return 0;
195 }
196
197 if(getifaddrs(&ifaddr) == -1) {
198 PERROR("Could not get interface list");
199 ret = -1;
200 goto end;
201
202 }
203
204 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
205
206 if(!strcmp(ifaceName, ifa->ifa_name)) {
207 ret = 1;
208 goto end;
209 }
210
211 }
212
213 ret = 0;
214 DBG("Interface not found: %s\n", ifaceName);
215
216 end:
217 freeifaddrs(ifaddr);
218 return ret;
219 }
220
221 static int
222 getInterfaceFlags(char* ifaceName, unsigned int* flags)
223 {
224
225 int ret;
226 struct ifaddrs *ifaddr, *ifa;
227
228 if(!strlen(ifaceName)) {
229 DBG("interfaceExists called for an empty interface!");
230 return 0;
231 }
232
233 if(getifaddrs(&ifaddr) == -1) {
234 PERROR("Could not get interface list");
235 ret = -1;
236 goto end;
237
238 }
239
240 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
241
242 if(!strcmp(ifaceName, ifa->ifa_name)) {
243 *flags = ifa->ifa_flags;
244 ret = 1;
245 goto end;
246 }
247
248 }
249
250 ret = 0;
251 DBG("Interface not found: %s\n", ifaceName);
252
253 end:
254 freeifaddrs(ifaddr);
255 return ret;
256 }
257
258
259 /* Try getting addr address of family family from interface ifaceName.
260 Return 1 on success, 0 when no suitable address available, -1 on failure.
261 */
262 static int
263 getInterfaceAddress(char* ifaceName, int family, struct in_addr* addr) {
264
265 int ret;
266 struct ifaddrs *ifaddr, *ifa;
267
268 if(getifaddrs(&ifaddr) == -1) {
269 PERROR("Could not get interface list");
270 ret = -1;
271 goto end;
272
273 }
274
275 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
276
277 if(!strcmp(ifaceName, ifa->ifa_name) && ifa->ifa_addr->sa_family == family) {
278
279 *addr = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr;
280 ret = 1;
281 goto end;
282
283 }
284
285 }
286
287 ret = 0;
288 DBG("Interface not found: %s\n", ifaceName);
289
290 end:
291
292 freeifaddrs(ifaddr);
293 return ret;
294 }
295
296
297 /* Try getting hwAddrSize bytes of ifaceName hardware address,
298 and place them in hwAddr. Return 1 on success, 0 when no suitable
299 hw address available, -1 on failure.
300 */
301 static int
302 getHwAddress (char* ifaceName, unsigned char* hwAddr, int hwAddrSize)
303 {
304
305 int ret;
306 if(!strlen(ifaceName))
307 return 0;
308
309 /* BSD* - AF_LINK gives us access to the hw address via struct sockaddr_dl */
310 #ifdef AF_LINK
311
312 struct ifaddrs *ifaddr, *ifa;
313
314 if(getifaddrs(&ifaddr) == -1) {
315 PERROR("Could not get interface list");
316 ret = -1;
317 goto end;
318
319 }
320
321 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
322
323 if(!strcmp(ifaceName, ifa->ifa_name) && ifa->ifa_addr->sa_family == AF_LINK) {
324
325 struct sockaddr_dl* sdl = (struct sockaddr_dl *)ifa->ifa_addr;
326 if(sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_L2VLAN) {
327
328 memcpy(hwAddr, LLADDR(sdl),
329 hwAddrSize <= sizeof(sdl->sdl_data) ?
330 hwAddrSize : sizeof(sdl->sdl_data));
331 ret = 1;
332 goto end;
333 } else {
334 DBGV("Unsupported hardware address family on %s\n", ifaceName);
335 ret = 0;
336 goto end;
337 }
338 }
339
340 }
341
342 ret = 0;
343 DBG("Interface not found: %s\n", ifaceName);
344
345 end:
346
347 freeifaddrs(ifaddr);
348 return ret;
349
350 /* Linux, basically */
351 #else
352
353 int sockfd;
354 struct ifreq ifr;
355
356 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
357
358 if(sockfd < 0) {
359 PERROR("Could not open test socket");
360 return -1;
361 }
362
363 memset(&ifr, 0, sizeof(struct ifreq));
364
365 strncpy(ifr.ifr_name, ifaceName, IFACE_NAME_LENGTH);
366
367 if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
368 DBGV("failed to request hardware address for %s", ifaceName);
369 ret = -1;
370 goto end;
371 }
372
373
374 int af = ifr.ifr_hwaddr.sa_family;
375
376 if ( af == ARPHRD_ETHER
377 || af == ARPHRD_IEEE802
378 #ifdef ARPHRD_INFINIBAND
379 || af == ARPHRD_INFINIBAND
380 #endif
381 ) {
382 memcpy(hwAddr, ifr.ifr_hwaddr.sa_data, hwAddrSize);
383 ret = 1;
384 } else {
385 DBGV("Unsupported hardware address family on %s\n", ifaceName);
386 ret = 0;
387 }
388 end:
389 close(sockfd);
390 return ret;
391
392 #endif /* AF_LINK */
393
394 }
395
396 static Boolean getInterfaceInfo(char* ifaceName, InterfaceInfo* ifaceInfo)
397 {
398
399 int res;
400
401 res = interfaceExists(ifaceName);
402
403 if (res == -1) {
404
405 return FALSE;
406
407 } else if (res == 0) {
408
409 ERROR("Interface %s does not exist.\n", ifaceName);
410 return FALSE;
411 }
412
413 res = getInterfaceAddress(ifaceName, ifaceInfo->addressFamily, &ifaceInfo->afAddress);
414
415 if (res == -1) {
416
417 return FALSE;
418
419 }
420
421 ifaceInfo->hasAfAddress = res;
422
423 res = getHwAddress(ifaceName, (unsigned char*)ifaceInfo->hwAddress, 6);
424
425 if (res == -1) {
426
427 return FALSE;
428
429 }
430
431 ifaceInfo->hasHwAddress = res;
432
433 res = getInterfaceFlags(ifaceName, &ifaceInfo->flags);
434
435 if (res == -1) {
436
437 return FALSE;
438
439 }
440
441 return TRUE;
442
443 }
444
445 Boolean
446 testInterface(char * ifaceName, RunTimeOpts* rtOpts)
447 {
448
449 InterfaceInfo info;
450
451 info.addressFamily = AF_INET;
452
453 if(getInterfaceInfo(ifaceName, &info) != 1)
454 return FALSE;
455
456 switch(rtOpts->transport) {
457
458 case UDP_IPV4:
459 if(!info.hasAfAddress) {
460 ERROR("Interface %s has no IPv4 address set\n", ifaceName);
461 return FALSE;
462 }
463 break;
464
465 case IEEE_802_3:
466 if(!info.hasHwAddress) {
467 ERROR("Interface %s has no supported hardware address - possibly not an Ethernet interface\n", ifaceName);
468 return FALSE;
469 }
470 break;
471
472 default:
473 ERROR("Unsupported transport: %d\n", rtOpts->transport);
474 return FALSE;
475
476 }
477
478 if(!(info.flags & IFF_UP) || !(info.flags & IFF_RUNNING))
479 WARNING("Interface %s seems to be down. PTPd will not operate correctly until it's up.\n", ifaceName);
480
481 if(info.flags & IFF_LOOPBACK)
482 WARNING("Interface %s is a loopback interface.\n", ifaceName);
483
484 if(!(info.flags & IFF_MULTICAST)
485 && rtOpts->transport==UDP_IPV4
486 && rtOpts->ip_mode != IPMODE_UNICAST) {
487 WARNING("Interface %s is not multicast capable.\n", ifaceName);
488 }
489
490 return TRUE;
491
492 }
493
494 /**
495 * Init the multcast for specific IPv4 address
496 *
497 * @param netPath
498 * @param multicastAddr
499 *
500 * @return TRUE if successful
501 */
502 static Boolean
503 netInitMulticastIPv4(NetPath * netPath, Integer32 multicastAddr)
504 {
505 struct ip_mreq imr;
506
507 /* multicast send only on specified interface */
508 imr.imr_multiaddr.s_addr = multicastAddr;
509 imr.imr_interface.s_addr = netPath->interfaceAddr.s_addr;
510 if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_IF,
511 &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0
512 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_IF,
513 &imr.imr_interface.s_addr, sizeof(struct in_addr))
514 < 0) {
515 PERROR("failed to enable multi-cast on the interface");
516 return FALSE;
517 }
518 /* join multicast group (for receiving) on specified interface */
519 if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
520 &imr, sizeof(struct ip_mreq)) < 0
521 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
522 &imr, sizeof(struct ip_mreq)) < 0) {
523 PERROR("failed to join the multi-cast group");
524 return FALSE;
525 }
526 return TRUE;
527 }
528
529 /**
530 * Init the multcast (both General and Peer)
531 *
532 * @param netPath
533 * @param rtOpts
534 *
535 * @return TRUE if successful
536 */
537 static Boolean
538 netInitMulticast(NetPath * netPath, RunTimeOpts * rtOpts)
539 {
540 struct in_addr netAddr;
541 char addrStr[NET_ADDRESS_LENGTH+1];
542
543
544 /* Init General multicast IP address */
545 strncpy(addrStr, DEFAULT_PTP_DOMAIN_ADDRESS, NET_ADDRESS_LENGTH);
546 if (!inet_aton(addrStr, &netAddr)) {
547 ERROR("failed to encode multicast address: %s\n", addrStr);
548 return FALSE;
549 }
550
551 netPath->multicastAddr = netAddr.s_addr;
552 if(!netInitMulticastIPv4(netPath, netPath->multicastAddr)) {
553 return FALSE;
554 }
555
556 /* End of General multicast Ip address init */
557
558
559 /* Init Peer multicast IP address */
560 strncpy(addrStr, PEER_PTP_DOMAIN_ADDRESS, NET_ADDRESS_LENGTH);
561 if (!inet_aton(addrStr, &netAddr)) {
562 ERROR("failed to encode multi-cast address: %s\n", addrStr);
563 return FALSE;
564 }
565 netPath->peerMulticastAddr = netAddr.s_addr;
566 if(!netInitMulticastIPv4(netPath, netPath->peerMulticastAddr)) {
567 return FALSE;
568 }
569 /* End of Peer multicast Ip address init */
570
571 return TRUE;
572 }
573
574 static Boolean
575 netSetMulticastTTL(int sockfd, int ttl) {
576
577 #ifdef __OpenBSD__
578 uint8_t temp = (uint8_t) ttl;
579 #else
580 int temp = ttl;
581 #endif
582
583 if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
584 &temp, sizeof(temp)) < 0) {
585 PERROR("Failed to set socket multicast time-to-live");
586 return FALSE;
587 }
588 return TRUE;
589 }
590
591 static Boolean
592 netSetMulticastLoopback(NetPath * netPath, Boolean value) {
593 #ifdef __OpenBSD__
594 uint8_t temp = value ? 1 : 0;
595 #else
596 int temp = value ? 1 : 0;
597 #endif
598 DBG("Going to set multicast loopback with %d \n", temp);
599
600 if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_LOOP,
601 &temp, sizeof(temp)) < 0) {
602 PERROR("Failed to set multicast loopback");
603 return FALSE;
604 }
605
606 return TRUE;
607 }
608
609 #if defined(SO_TIMESTAMPING) && defined(SO_TIMESTAMPNS)
610 static Boolean
611 getTxTimestamp(NetPath* netPath,TimeInternal* timeStamp) {
612 extern PtpClock *G_ptpClock;
613 ssize_t length;
614 fd_set tmpSet;
615 struct timeval timeOut = {0,0};
616 int val = 1;
617 if(netPath->txTimestampFailure)
618 goto end;
619
620 FD_ZERO(&tmpSet);
621 FD_SET(netPath->eventSock, &tmpSet);
622
623 if(select(netPath->eventSock + 1, &tmpSet, NULL, NULL, &timeOut) > 0) {
624 if (FD_ISSET(netPath->eventSock, &tmpSet)) {
625 length = netRecvEvent(G_ptpClock->msgIbuf, timeStamp,
626 netPath, MSG_ERRQUEUE);
627
628 if (length > 0) {
629 DBG("Grabbed sent msg via errqueue: %d bytes, at %d.%d\n", length, timeStamp->seconds, timeStamp->nanoseconds);
630 return TRUE;
631 } else if (length < 0) {
632 DBG("Failed to poll error queue for SO_TIMESTAMPING transmit time");
633 G_ptpClock->counters.messageRecvErrors++;
634 goto end;
635 } else if (length == 0) {
636 DBG("Received no data from TX error queue");
637 goto end;
638 }
639 }
640 } else {
641 DBG("SO_TIMESTAMPING - t timeout on TX timestamp - will use loop from now on\n");
642 return FALSE;
643 }
644 end:
645 if(setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMPNS, &val, sizeof(int)) < 0) {
646 DBG("gettxtimestamp: failed to revert to SO_TIMESTAMPNS");
647 }
648
649 return FALSE;
650 }
651 #endif /* SO_TIMESTAMPING */
652
653
654 /**
655 * Initialize timestamping of packets
656 *
657 * @param netPath
658 *
659 * @return TRUE if successful
660 */
661 static Boolean
662 netInitTimestamping(NetPath * netPath, RunTimeOpts * rtOpts)
663 {
664
665 int val = 1;
666 Boolean result = TRUE;
667 #if defined(SO_TIMESTAMPING) && defined(SO_TIMESTAMPNS)/* Linux - current API */
668 DBG("netInitTimestamping: trying to use SO_TIMESTAMPING\n");
669 val = SOF_TIMESTAMPING_TX_SOFTWARE |
670 SOF_TIMESTAMPING_RX_SOFTWARE |
671 SOF_TIMESTAMPING_SOFTWARE;
672
673 /* unless compiled with PTPD_EXPERIMENTAL, check if we support the desired tstamp capabilities */
674 #ifndef PTPD_EXPERIMENTAL
675 #ifdef ETHTOOL_GET_TS_INFO
676
677 struct ethtool_ts_info tsInfo;
678 struct ifreq ifRequest;
679 int res;
680
681 memset(&tsInfo, 0, sizeof(tsInfo));
682 memset(&ifRequest, 0, sizeof(ifRequest));
683 tsInfo.cmd = ETHTOOL_GET_TS_INFO;
684 strncpy( ifRequest.ifr_name, rtOpts->ifaceName, IFNAMSIZ - 1);
685 ifRequest.ifr_data = (char *) &tsInfo;
686 res = ioctl(netPath->eventSock, SIOCETHTOOL, &ifRequest);
687
688 if (res < 0) {
689 PERROR("Could not retrieve ethtool timestamping capabilities for %s - reverting to SO_TIMESTAMPNS",
690 rtOpts->ifaceName);
691 val = 1;
692 netPath->txTimestampFailure = FALSE;
693 } else if((tsInfo.so_timestamping & val) != val) {
694 DBGV("Required SO_TIMESTAMPING flags not supported - reverting to SO_TIMESTAMPNS\n");
695 val = 1;
696 netPath->txTimestampFailure = TRUE;
697 }
698 #else
699 netPath->txTimestampFailure = FALSE;
700 val = 1;
701 #endif /* ETHTOOL_GET_TS_INFO */
702 #endif /* PTPD_EXPERIMENTAL */
703
704 if((val==1 && (setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMPNS, &val, sizeof(int)) < 0)) ||
705 (setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMPING, &val, sizeof(int)) < 0)) {
706 PERROR("netInitTimestamping: failed to enable SO_TIMESTAMP%s",(val==1)?"NS":"ING");
707 result = FALSE;
708 } else {
709 DBG("SO_TIMESTAMP%s initialised\n",(val==1)?"NS":"ING");
710 }
711 #elif defined(SO_TIMESTAMPNS) /* Linux, Apple */
712 DBG("netInitTimestamping: trying to use SO_TIMESTAMPNS\n");
713
714 if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMPNS, &val, sizeof(int)) < 0) {
715 PERROR("netInitTimestamping: failed to enable SO_TIMESTAMPNS");
716 result = FALSE;
717 }
718 #elif defined(SO_BINTIME) /* FreeBSD */
719 DBG("netInitTimestamping: trying to use SO_BINTIME\n");
720
721 if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_BINTIME, &val, sizeof(int)) < 0) {
722 PERROR("netInitTimestamping: failed to enable SO_BINTIME");
723 result = FALSE;
724 }
725 #else
726 result = FALSE;
727 #endif
728
729 /* fallback method */
730 #if defined(SO_TIMESTAMP) /* Linux, Apple, FreeBSD */
731 if (!result) {
732 DBG("netInitTimestamping: trying to use SO_TIMESTAMP\n");
733
734 if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMP, &val, sizeof(int)) < 0) {
735 PERROR("netInitTimestamping: failed to enable SO_TIMESTAMP");
736 result = FALSE;
737 }
738 result = TRUE;
739 }
740 #endif
741
742 return result;
743 }
744
745 Boolean
746 hostLookup(const char* hostname, Integer32* addr)
747 {
748 if (hostname[0]) {
749 /* Attempt a DNS lookup first. */
750 struct hostent *host;
751 host = gethostbyname2(hostname, AF_INET);
752 if (host != NULL) {
753 if (host->h_length != 4) {
754 PERROR("unicast host resolved to non ipv4"
755 "address");
756 return FALSE;
757 }
758 *addr =
759 *(uint32_t *)host->h_addr_list[0];
760 return TRUE;
761 } else {
762 struct in_addr netAddr;
763 /* Maybe it's a dotted quad. */
764 if (!inet_aton(hostname, &netAddr)) {
765 ERROR("failed to encode unicast address: %s\n",
766 hostname);
767 return FALSE;
768 *addr = netAddr.s_addr;
769 return TRUE;
770 }
771 }
772 }
773
774 return FALSE;
775
776 }
777
778
779 /**
780 * Init all network transports
781 *
782 * @param netPath
783 * @param rtOpts
784 * @param ptpClock
785 *
786 * @return TRUE if successful
787 */
788 Boolean
789 netInit(NetPath * netPath, RunTimeOpts * rtOpts, PtpClock * ptpClock)
790 {
791 int temp;
792 struct sockaddr_in addr;
793
794 #ifdef PTPD_PCAP
795 struct bpf_program program;
796 char errbuf[PCAP_ERRBUF_SIZE];
797 #endif
798
799 DBG("netInit\n");
800
801 #ifdef PTPD_PCAP
802 netPath->pcapEvent = NULL;
803 netPath->pcapGeneral = NULL;
804 netPath->pcapEventSock = -1;
805 netPath->pcapGeneralSock = -1;
806 #endif
807 netPath->generalSock = -1;
808 netPath->eventSock = -1;
809
810 #ifdef PTPD_PCAP
811 if (rtOpts->transport == IEEE_802_3) {
812 netPath->headerOffset = PACKET_BEGIN_ETHER;
813 #ifdef HAVE_STRUCT_ETHER_ADDR_OCTET
814 memcpy(netPath->etherDest.octet, ether_aton(PTP_ETHER_DST), ETHER_ADDR_LEN);
815 memcpy(netPath->peerEtherDest.octet, ether_aton(PTP_ETHER_PEER), ETHER_ADDR_LEN);
816 #else
817 memcpy(netPath->etherDest.ether_addr_octet, ether_aton(PTP_ETHER_DST), ETHER_ADDR_LEN);
818 memcpy(netPath->peerEtherDest.ether_addr_octet, ether_aton(PTP_ETHER_PEER), ETHER_ADDR_LEN);
819 #endif /* HAVE_STRUCT_ETHER_ADDR_OCTET */
820 } else
821 #endif
822 netPath->headerOffset = PACKET_BEGIN_UDP;
823
824 /* open sockets */
825 if ((netPath->eventSock = socket(PF_INET, SOCK_DGRAM,
826 IPPROTO_UDP)) < 0
827 || (netPath->generalSock = socket(PF_INET, SOCK_DGRAM,
828 IPPROTO_UDP)) < 0) {
829 PERROR("failed to initialize sockets");
830 return FALSE;
831 }
832
833 if(!testInterface(rtOpts->ifaceName, rtOpts))
834 return FALSE;
835
836 netPath->interfaceInfo.addressFamily = AF_INET;
837
838 /* the if is here only to get rid of an unused result warning. */
839 if( getInterfaceInfo(rtOpts->ifaceName, &netPath->interfaceInfo)!= 1)
840 return FALSE;
841
842 /* No HW address, we'll use the protocol address to form interfaceID -> clockID */
843 if( !netPath->interfaceInfo.hasHwAddress && netPath->interfaceInfo.hasAfAddress ) {
844 uint32_t addr = netPath->interfaceInfo.afAddress.s_addr;
845 memcpy(netPath->interfaceID, &addr, 2);
846 memcpy(netPath->interfaceID + 4, &addr + 2, 2);
847 /* Initialise interfaceID with hardware address */
848 } else {
849 memcpy(&netPath->interfaceID, &netPath->interfaceInfo.hwAddress,
850 sizeof(netPath->interfaceID) <= sizeof(netPath->interfaceInfo.hwAddress) ?
851 sizeof(netPath->interfaceID) : sizeof(netPath->interfaceInfo.hwAddress)
852 );
853 }
854
855 DBG("Listening on IP: %s\n",inet_ntoa(netPath->interfaceInfo.afAddress));
856
857 #ifdef PTPD_PCAP
858 if (rtOpts->pcap == TRUE) {
859 int promisc = (rtOpts->transport == IEEE_802_3 ) ? 1 : 0;
860 if ((netPath->pcapEvent = pcap_open_live(rtOpts->ifaceName,
861 PACKET_SIZE, promisc,
862 PCAP_TIMEOUT,
863 errbuf)) == NULL) {
864 PERROR("failed to open event pcap");
865 return FALSE;
866 }
867 if (pcap_compile(netPath->pcapEvent, &program,
868 ( rtOpts->transport == IEEE_802_3 ) ?
869 "ether proto 0x88f7":
870 ( rtOpts->ip_mode != IPMODE_MULTICAST ) ?
871 "udp port 319" :
872 "host (224.0.1.129 or 224.0.0.107) and udp port 319" ,
873 1, 0) < 0) {
874 PERROR("failed to compile pcap event filter");
875 pcap_perror(netPath->pcapEvent, "ptpd2");
876 return FALSE;
877 }
878 if (pcap_setfilter(netPath->pcapEvent, &program) < 0) {
879 PERROR("failed to set pcap event filter");
880 return FALSE;
881 }
882 pcap_freecode(&program);
883 if ((netPath->pcapEventSock =
884 pcap_get_selectable_fd(netPath->pcapEvent)) < 0) {
885 PERROR("failed to get pcap event fd");
886 return FALSE;
887 }
888 if ((netPath->pcapGeneral = pcap_open_live(rtOpts->ifaceName,
889 PACKET_SIZE, promisc,
890 PCAP_TIMEOUT,
891 errbuf)) == NULL) {
892 PERROR("failed to open general pcap");
893 return FALSE;
894 }
895 if (rtOpts->transport != IEEE_802_3) {
896 if (pcap_compile(netPath->pcapGeneral, &program,
897 ( rtOpts->ip_mode != IPMODE_MULTICAST ) ?
898 "udp port 320" :
899 "host (224.0.1.129 or 224.0.0.107) and udp port 320" ,
900 1, 0) < 0) {
901 PERROR("failed to compile pcap general filter");
902 pcap_perror(netPath->pcapGeneral, "ptpd2");
903 return FALSE;
904 }
905 if (pcap_setfilter(netPath->pcapGeneral, &program) < 0) {
906 PERROR("failed to set pcap general filter");
907 return FALSE;
908 }
909 pcap_freecode(&program);
910 if ((netPath->pcapGeneralSock =
911 pcap_get_selectable_fd(netPath->pcapGeneral)) < 0) {
912 PERROR("failed to get pcap general fd");
913 return FALSE;
914 }
915 }
916 }
917 #endif
918
919 #ifdef PTPD_PCAP
920 if(rtOpts->transport == IEEE_802_3) {
921 close(netPath->eventSock);
922 netPath->eventSock = -1;
923 close(netPath->generalSock);
924 netPath->generalSock = -1;
925 /* TX timestamp is not generated for PCAP mode and Ethernet transport */
926 #ifdef SO_TIMESTAMPING
927 netPath->txTimestampFailure = TRUE;
928 #endif /* SO_TIMESTAMPING */
929 } else {
930 #endif
931 /* save interface address for IGMP refresh */
932 netPath->interfaceAddr = netPath->interfaceInfo.afAddress;
933
934 DBG("Local IP address used : %s \n", inet_ntoa(netPath->interfaceInfo.afAddress));
935
936 temp = 1; /* allow address reuse */
937 if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_REUSEADDR,
938 &temp, sizeof(int)) < 0
939 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_REUSEADDR,
940 &temp, sizeof(int)) < 0) {
941 DBG("failed to set socket reuse\n");
942 }
943 /* bind sockets */
944 /*
945 * need INADDR_ANY to allow receipt of multi-cast and uni-cast
946 * messages
947 */
948
949 /* why??? */
950 if (rtOpts->pidAsClockId) {
951 if (inet_pton(AF_INET, DEFAULT_PTP_DOMAIN_ADDRESS, &addr.sin_addr) < 0) {
952 PERROR("failed to convert address");
953 return FALSE;
954 }
955 } else
956 addr.sin_addr.s_addr = htonl(INADDR_ANY);
957
958 addr.sin_family = AF_INET;
959 addr.sin_port = htons(PTP_EVENT_PORT);
960 if (bind(netPath->eventSock, (struct sockaddr *)&addr,
961 sizeof(struct sockaddr_in)) < 0) {
962 PERROR("failed to bind event socket");
963 return FALSE;
964 }
965 addr.sin_port = htons(PTP_GENERAL_PORT);
966 if (bind(netPath->generalSock, (struct sockaddr *)&addr,
967 sizeof(struct sockaddr_in)) < 0) {
968 PERROR("failed to bind general socket");
969 return FALSE;
970 }
971
972 #ifdef USE_BINDTODEVICE
973 #ifdef linux
974 /*
975 * The following code makes sure that the data is only
976 * received on the specified interface. Without this option,
977 * it's possible to receive PTP from another interface, and
978 * confuse the protocol. Calling bind() with the IP address
979 * of the device instead of INADDR_ANY does not work.
980 *
981 * More info:
982 * http://developerweb.net/viewtopic.php?id=6471
983 * http://stackoverflow.com/questions/1207746/problems-with-so-bindtodevice-linux-socket-option
984 */
985
986 if ( rtOpts->ip_mode != IPMODE_HYBRID )
987 if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_BINDTODEVICE,
988 rtOpts->ifaceName, strlen(rtOpts->ifaceName)) < 0
989 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_BINDTODEVICE,
990 rtOpts->ifaceName, strlen(rtOpts->ifaceName)) < 0){
991 PERROR("failed to call SO_BINDTODEVICE on the interface");
992 return FALSE;
993 }
994 #endif
995 #endif
996
997 /* Set socket dscp */
998 if(rtOpts->dscpValue) {
999
1000 if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_TOS,
1001 &rtOpts->dscpValue, sizeof(int)) < 0
1002 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_TOS,
1003 &rtOpts->dscpValue, sizeof(int)) < 0) {
1004 PERROR("Failed to set socket DSCP bits");
1005 return FALSE;
1006 }
1007 }
1008
1009 /* send a uni-cast address if specified (useful for testing) */
1010 if(!hostLookup(rtOpts->unicastAddress, &netPath->unicastAddr)) {
1011 netPath->unicastAddr = 0;
1012 }
1013
1014
1015 if(rtOpts->ip_mode != IPMODE_UNICAST) {
1016
1017 /* init UDP Multicast on both Default and Peer addresses */
1018 if (!netInitMulticast(netPath, rtOpts))
1019 return FALSE;
1020
1021 /* set socket time-to-live */
1022 if(!netSetMulticastTTL(netPath->eventSock,rtOpts->ttl) ||
1023 !netSetMulticastTTL(netPath->generalSock,rtOpts->ttl))
1024 return FALSE;
1025
1026 /* start tracking TTL */
1027 netPath->ttlEvent = rtOpts->ttl;
1028 netPath->ttlGeneral = rtOpts->ttl;
1029 }
1030
1031 #ifdef SO_TIMESTAMPING
1032 /* Reset the failure indicator when (re)starting network */
1033 netPath->txTimestampFailure = FALSE;
1034 /* for SO_TIMESTAMPING we're receiving transmitted packets via ERRQUEUE */
1035 temp = 0;
1036 #else
1037 /* enable loopback */
1038 temp = 1;
1039 #endif
1040
1041 /* make timestamps available through recvmsg() */
1042 if (!netInitTimestamping(netPath,rtOpts)) {
1043 ERROR("Failed to enable packet time stamping\n");
1044 return FALSE;
1045 }
1046
1047 #ifdef SO_TIMESTAMPING
1048 /* If we failed to initialise SO_TIMESTAMPING, enable mcast loopback */
1049 if(netPath->txTimestampFailure)
1050 temp = 1;
1051 #endif
1052
1053 if(!netSetMulticastLoopback(netPath, temp)) {
1054 return FALSE;
1055 }
1056
1057 #ifdef PTPD_PCAP
1058 }
1059 #endif
1060
1061 /* Compile ACLs */
1062 if(rtOpts->timingAclEnabled) {
1063 freeIpv4AccessList(&netPath->timingAcl);
1064 netPath->timingAcl=createIpv4AccessList(rtOpts->timingAclPermitText,
1065 rtOpts->timingAclDenyText, rtOpts->timingAclOrder);
1066 }
1067 if(rtOpts->managementAclEnabled) {
1068 freeIpv4AccessList(&netPath->managementAcl);
1069 netPath->managementAcl=createIpv4AccessList(rtOpts->managementAclPermitText,
1070 rtOpts->managementAclDenyText, rtOpts->managementAclOrder);
1071 }
1072
1073 return TRUE;
1074 }
1075
1076 /*Check if data has been received*/
1077 int
1078 netSelect(TimeInternal * timeout, NetPath * netPath, fd_set *readfds)
1079 {
1080 int ret, nfds;
1081 struct timeval tv, *tv_ptr;
1082
1083
1084 #if defined PTPD_SNMP
1085 extern RunTimeOpts rtOpts;
1086 struct timeval snmp_timer_wait = { 0, 0}; // initialise to avoid unused warnings when SNMP disabled
1087 int snmpblock = 0;
1088 #endif
1089
1090 if (timeout) {
1091 if(isTimeInternalNegative(timeout)) {
1092 ERROR("Negative timeout attempted for select()\n");
1093 return -1;
1094 }
1095 tv.tv_sec = timeout->seconds;
1096 tv.tv_usec = timeout->nanoseconds / 1000;
1097 tv_ptr = &tv;
1098 } else {
1099 tv_ptr = NULL;
1100 }
1101
1102 FD_ZERO(readfds);
1103 nfds = 0;
1104 #ifdef PTPD_PCAP
1105 if (netPath->pcapEventSock >= 0) {
1106 FD_SET(netPath->pcapEventSock, readfds);
1107 if (netPath->pcapGeneralSock >= 0)
1108 FD_SET(netPath->pcapGeneralSock, readfds);
1109
1110 nfds = netPath->pcapEventSock;
1111 if (netPath->pcapEventSock < netPath->pcapGeneralSock)
1112 nfds = netPath->pcapGeneralSock;
1113
1114 } else if (netPath->eventSock >= 0) {
1115 #endif
1116 FD_SET(netPath->eventSock, readfds);
1117 if (netPath->generalSock >= 0)
1118 FD_SET(netPath->generalSock, readfds);
1119
1120 nfds = netPath->eventSock;
1121 if (netPath->eventSock < netPath->generalSock)
1122 nfds = netPath->generalSock;
1123 #ifdef PTPD_PCAP
1124 }
1125 #endif
1126 nfds++;
1127
1128 #if defined PTPD_SNMP
1129 if (rtOpts.snmp_enabled) {
1130 snmpblock = 1;
1131 if (tv_ptr) {
1132 snmpblock = 0;
1133 memcpy(&snmp_timer_wait, tv_ptr, sizeof(struct timeval));
1134 }
1135 snmp_select_info(&nfds, readfds, &snmp_timer_wait, &snmpblock);
1136 if (snmpblock == 0)
1137 tv_ptr = &snmp_timer_wait;
1138 }
1139 #endif
1140
1141 ret = select(nfds, readfds, 0, 0, tv_ptr);
1142
1143 if (ret < 0) {
1144 if (errno == EAGAIN || errno == EINTR)
1145 return 0;
1146 }
1147 #if defined PTPD_SNMP
1148 if (rtOpts.snmp_enabled) {
1149 /* Maybe we have received SNMP related data */
1150 if (ret > 0) {
1151 snmp_read(readfds);
1152 } else if (ret == 0) {
1153 snmp_timeout();
1154 run_alarms();
1155 }
1156 netsnmp_check_outstanding_agent_requests();
1157 }
1158 #endif
1159 return ret;
1160 }
1161
1162 /**
1163 * store received data from network to "buf" , get and store the
1164 * SO_TIMESTAMP value in "time" for an event message
1165 *
1166 * @note Should this function be merged with netRecvGeneral(), below?
1167 * Jan Breuer: I think that netRecvGeneral should be
1168 * simplified. Timestamp returned by this function is never
1169 * used. According to this, netInitTimestamping can be also simplified
1170 * to initialize timestamping only on eventSock.
1171 *
1172 * @param buf
1173 * @param time
1174 * @param netPath
1175 *
1176 * @return
1177 */
1178
1179 ssize_t
1180 netRecvEvent(Octet * buf, TimeInternal * time, NetPath * netPath, int flags)
1181 {
1182 ssize_t ret = 0;
1183 struct msghdr msg;
1184 struct iovec vec[1];
1185 struct sockaddr_in from_addr;
1186
1187 #ifdef PTPD_PCAP
1188 struct pcap_pkthdr *pkt_header;
1189 const u_char *pkt_data;
1190 #endif
1191
1192 union {
1193 struct cmsghdr cm;
1194 char control[256];
1195 } cmsg_un;
1196
1197 struct cmsghdr *cmsg;
1198
1199 #if defined(SO_TIMESTAMPNS) || defined(SO_TIMESTAMPING)
1200 struct timespec * ts;
1201 #elif defined(SO_BINTIME)
1202 struct bintime * bt;
1203 struct timespec ts;
1204 #endif
1205
1206 #if defined(SO_TIMESTAMP)
1207 struct timeval * tv;
1208 #endif
1209 Boolean timestampValid = FALSE;
1210
1211 #ifdef PTPD_PCAP
1212 if (netPath->pcapEvent == NULL) { /* Using sockets */
1213 #endif
1214 vec[0].iov_base = buf;
1215 vec[0].iov_len = PACKET_SIZE;
1216
1217 memset(&msg, 0, sizeof(msg));
1218 memset(&from_addr, 0, sizeof(from_addr));
1219 memset(buf, 0, PACKET_SIZE);
1220 memset(&cmsg_un, 0, sizeof(cmsg_un));
1221
1222 msg.msg_name = (caddr_t)&from_addr;
1223 msg.msg_namelen = sizeof(from_addr);
1224 msg.msg_iov = vec;
1225 msg.msg_iovlen = 1;
1226 msg.msg_control = cmsg_un.control;
1227 msg.msg_controllen = sizeof(cmsg_un.control);
1228 msg.msg_flags = 0;
1229
1230 ret = recvmsg(netPath->eventSock, &msg, flags | MSG_DONTWAIT);
1231 if (ret <= 0) {
1232 if (errno == EAGAIN || errno == EINTR)
1233 return 0;
1234
1235 return ret;
1236 };
1237 if (msg.msg_flags & MSG_TRUNC) {
1238 ERROR("received truncated message\n");
1239 return 0;
1240 }
1241 /* get time stamp of packet */
1242 if (!time) {
1243 ERROR("null receive time stamp argument\n");
1244 return 0;
1245 }
1246 if (msg.msg_flags & MSG_CTRUNC) {
1247 ERROR("received truncated ancillary data\n");
1248 return 0;
1249 }
1250
1251 #if defined(HAVE_DECL_MSG_ERRQUEUE) && HAVE_DECL_MSG_ERRQUEUE
1252 if(!(flags & MSG_ERRQUEUE))
1253 #endif
1254 netPath->lastRecvAddr = from_addr.sin_addr.s_addr;
1255 netPath->receivedPackets++;
1256
1257 if (msg.msg_controllen <= 0) {
1258 ERROR("received short ancillary data (%ld/%ld)\n",
1259 (long)msg.msg_controllen, (long)sizeof(cmsg_un.control));
1260
1261 return 0;
1262 }
1263
1264 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
1265 cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1266 if (cmsg->cmsg_level == SOL_SOCKET) {
1267 #if defined(SO_TIMESTAMPING) && defined(SO_TIMESTAMPNS)
1268 if(cmsg->cmsg_type == SO_TIMESTAMPING ||
1269 cmsg->cmsg_type == SO_TIMESTAMPNS) {
1270 ts = (struct timespec *)CMSG_DATA(cmsg);
1271 time->seconds = ts->tv_sec;
1272 time->nanoseconds = ts->tv_nsec;
1273 timestampValid = TRUE;
1274 DBG("rcvevent: SO_TIMESTAMP%s %s time stamp: %us %dns\n", netPath->txTimestampFailure ?
1275 "NS" : "ING",
1276 (flags & MSG_ERRQUEUE) ? "(TX)" : "(RX)" , time->seconds, time->nanoseconds);
1277 break;
1278 }
1279 #elif defined(SO_TIMESTAMPNS)
1280 if(cmsg->cmsg_type == SCM_TIMESTAMPNS) {
1281 ts = (struct timespec *)CMSG_DATA(cmsg);
1282 time->seconds = ts->tv_sec;
1283 time->nanoseconds = ts->tv_nsec;
1284 timestampValid = TRUE;
1285 DBGV("kernel NANO recv time stamp %us %dns\n",
1286 time->seconds, time->nanoseconds);
1287 break;
1288 }
1289 #elif defined(SO_BINTIME)
1290 if(cmsg->cmsg_type == SCM_BINTIME) {
1291 bt = (struct bintime *)CMSG_DATA(cmsg);
1292 bintime2timespec(bt, &ts);
1293 time->seconds = ts.tv_sec;
1294 time->nanoseconds = ts.tv_nsec;
1295 timestampValid = TRUE;
1296 DBGV("kernel NANO recv time stamp %us %dns\n",
1297 time->seconds, time->nanoseconds);
1298 break;
1299 }
1300 #endif
1301
1302 #if defined(SO_TIMESTAMP)
1303 if(cmsg->cmsg_type == SCM_TIMESTAMP) {
1304 tv = (struct timeval *)CMSG_DATA(cmsg);
1305 time->seconds = tv->tv_sec;
1306 time->nanoseconds = tv->tv_usec * 1000;
1307 timestampValid = TRUE;
1308 DBGV("kernel MICRO recv time stamp %us %dns\n",
1309 time->seconds, time->nanoseconds);
1310 }
1311 #endif
1312 }
1313 }
1314
1315 if (!timestampValid) {
1316 /*
1317 * do not try to get by with recording the time here, better
1318 * to fail because the time recorded could be well after the
1319 * message receive, which would put a big spike in the
1320 * offset signal sent to the clock servo
1321 */
1322 DBG("netRecvEvent: no receive time stamp\n");
1323 return 0;
1324 }
1325 #ifdef PTPD_PCAP
1326 }
1327 #endif
1328
1329 #ifdef PTPD_PCAP
1330 else { /* Using PCAP */
1331 /* Discard packet on socket */
1332 if (netPath->eventSock >= 0) {
1333 recv(netPath->eventSock, buf, PACKET_SIZE, MSG_DONTWAIT);
1334 }
1335
1336 if ((ret = pcap_next_ex(netPath->pcapEvent, &pkt_header,
1337 &pkt_data)) < 1) {
1338 if (ret < 0)
1339 DBGV("netRecvEvent: pcap_next_ex failed %s\n",
1340 pcap_geterr(netPath->pcapEvent));
1341 return 0;
1342 }
1343
1344 /* Make sure this is IP (could dot1q get here?) */
1345 if( ntohs(*(u_short *)(pkt_data + 12)) != ETHERTYPE_IP)
1346 DBGV("PCAP payload received is not Ethernet: 0x%04x\n",
1347 ntohs(*(u_short *)(pkt_data + 12)));
1348 /* Retrieve source IP from the payload - 14 eth + 12 IP */
1349 netPath->lastRecvAddr = *(Integer32 *)(pkt_data + 26);
1350
1351 netPath->receivedPackets++;
1352 /* XXX Total cheat */
1353 memcpy(buf, pkt_data + netPath->headerOffset,
1354 pkt_header->caplen - netPath->headerOffset);
1355 time->seconds = pkt_header->ts.tv_sec;
1356 time->nanoseconds = pkt_header->ts.tv_usec * 1000;
1357 timestampValid = TRUE;
1358 DBGV("netRecvEvent: kernel PCAP recv time stamp %us %dns\n",
1359 time->seconds, time->nanoseconds);
1360 fflush(NULL);
1361 ret = pkt_header->caplen - netPath->headerOffset;
1362 }
1363 #endif
1364 return ret;
1365 }
1366
1367
1368
1369 /**
1370 *
1371 * store received data from network to "buf" get and store the
1372 * SO_TIMESTAMP value in "time" for a general message
1373 *
1374 * @param buf
1375 * @param time
1376 * @param netPath
1377 *
1378 * @return
1379 */
1380
1381 ssize_t
1382 netRecvGeneral(Octet * buf, NetPath * netPath)
1383 {
1384 ssize_t ret = 0;
1385 struct sockaddr_in from_addr;
1386
1387 #ifdef PTPD_PCAP
1388 struct pcap_pkthdr *pkt_header;
1389 const u_char *pkt_data;
1390 #endif
1391 socklen_t from_addr_len = sizeof(from_addr);
1392
1393 #ifdef PTPD_PCAP
1394 if (netPath->pcapGeneral == NULL) {
1395 #endif
1396 ret=recvfrom(netPath->generalSock, buf, PACKET_SIZE, MSG_DONTWAIT, (struct sockaddr*)&from_addr, &from_addr_len);
1397 netPath->lastRecvAddr = from_addr.sin_addr.s_addr;
1398 return ret;
1399 #ifdef PTPD_PCAP
1400 }
1401 #endif
1402
1403 #ifdef PTPD_PCAP
1404 else { /* Using PCAP */
1405 /* Discard packet on socket */
1406 if (netPath->generalSock >= 0)
1407 recv(netPath->generalSock, buf, PACKET_SIZE, MSG_DONTWAIT);
1408
1409
1410 if (( ret = pcap_next_ex(netPath->pcapGeneral, &pkt_header,
1411 &pkt_data)) < 1) {
1412 if (ret < 0)
1413 DBGV("netRecvGeneral: pcap_next_ex failed %d %s\n",
1414 ret, pcap_geterr(netPath->pcapGeneral));
1415 return 0;
1416 }
1417 /* Make sure this is IP (could dot1q get here?) */
1418 if( ntohs(*(u_short *)(pkt_data + 12)) != ETHERTYPE_IP)
1419 DBGV("PCAP payload received is not Ethernet: 0x%04x\n",
1420 ntohs(*(u_short *)(pkt_data + 12)));
1421 /* Retrieve source IP from the payload - 14 eth + 12 IP src*/
1422 netPath->lastRecvAddr = *(Integer32 *)(pkt_data + 26);
1423
1424 netPath->receivedPackets++;
1425 /* XXX Total cheat */
1426 memcpy(buf, pkt_data + netPath->headerOffset,
1427 pkt_header->caplen - netPath->headerOffset);
1428 fflush(NULL);
1429 ret = pkt_header->caplen - netPath->headerOffset;
1430 }
1431 #endif
1432 return ret;
1433 }
1434
1435
1436 #ifdef PTPD_PCAP
1437 ssize_t
1438 netSendPcapEther(Octet * buf, UInteger16 length,
1439 struct ether_addr * dst, struct ether_addr * src,
1440 pcap_t * pcap) {
1441 Octet ether[ETHER_HDR_LEN + PACKET_SIZE];
1442 #ifdef HAVE_STRUCT_ETHER_ADDR_OCTET
1443 memcpy(ether, dst->octet, ETHER_ADDR_LEN);
1444 memcpy(ether + ETHER_ADDR_LEN, src->octet, ETHER_ADDR_LEN);
1445 #else
1446 memcpy(ether, dst->ether_addr_octet, ETHER_ADDR_LEN);
1447 memcpy(ether + ETHER_ADDR_LEN, src->ether_addr_octet, ETHER_ADDR_LEN);
1448 #endif /* HAVE_STRUCT_ETHER_ADDR_OCTET */
1449 *((short *)ðer[2 * ETHER_ADDR_LEN]) = htons(PTP_ETHER_TYPE);
1450 memcpy(ether + ETHER_HDR_LEN, buf, length);
1451
1452 return pcap_inject(pcap, ether, ETHER_HDR_LEN + length);
1453 }
1454 #endif
1455
1456 //
1457 // alt_dst: alternative destination.
1458 // if filled, send to this unicast dest;
1459 // if zero, do the normal operation (send to unicast with -u, or send to the multcast group)
1460 //
1461 ///
1462 /// TODO: merge these 2 functions into one
1463 ///
1464 ssize_t
1465 netSendEvent(Octet * buf, UInteger16 length, NetPath * netPath,
1466 RunTimeOpts *rtOpts, Integer32 alt_dst, TimeInternal * tim)
1467 {
1468 ssize_t ret;
1469 struct sockaddr_in addr;
1470
1471 addr.sin_family = AF_INET;
1472 addr.sin_port = htons(PTP_EVENT_PORT);
1473
1474 #ifdef PTPD_PCAP
1475 /* In PCAP Ethernet mode, we use pcapEvent for receiving all messages
1476 * and pcapGeneral for sending all messages
1477 */
1478 if ((netPath->pcapGeneral != NULL) && (rtOpts->transport == IEEE_802_3 )) {
1479 ret = netSendPcapEther(buf, length,
1480 &netPath->etherDest,
1481 (struct ether_addr *)netPath->interfaceID,
1482 netPath->pcapGeneral);
1483
1484 if (ret <= 0)
1485 DBG("Error sending ether multicast event message\n");
1486 else
1487 netPath->sentPackets++;
1488 } else {
1489 #endif
1490 if (netPath->unicastAddr || alt_dst ) {
1491 if (netPath->unicastAddr) {
1492 addr.sin_addr.s_addr = netPath->unicastAddr;
1493 } else {
1494 addr.sin_addr.s_addr = alt_dst;
1495 }
1496
1497 /*
1498 * This function is used for PTP only anyway...
1499 * If we're sending to a unicast address, set the UNICAST flag.
1500 */
1501 *(char *)(buf + 6) |= PTP_UNICAST;
1502
1503 ret = sendto(netPath->eventSock, buf, length, 0,
1504 (struct sockaddr *)&addr,
1505 sizeof(struct sockaddr_in));
1506 if (ret <= 0)
1507 DBG("Error sending unicast event message\n");
1508 else
1509 netPath->sentPackets++;
1510 #ifndef SO_TIMESTAMPING
1511 /*
1512 * Need to forcibly loop back the packet since
1513 * we are not using multicast.
1514 */
1515
1516 addr.sin_addr.s_addr = netPath->interfaceAddr.s_addr;
1517 ret = sendto(netPath->eventSock, buf, length, 0,
1518 (struct sockaddr *)&addr,
1519 sizeof(struct sockaddr_in));
1520 if (ret <= 0)
1521 DBG("Error looping back unicast event message\n");
1522 #else
1523 if(!netPath->txTimestampFailure) {
1524 if(!getTxTimestamp(netPath, tim)) {
1525 netPath->txTimestampFailure = TRUE;
1526 if (tim) {
1527 clearTime(tim);
1528 }
1529 }
1530 }
1531
1532 if(netPath->txTimestampFailure)
1533 {
1534 /* We've had a TX timestamp receipt timeout - falling back to packet looping */
1535 addr.sin_addr.s_addr = netPath->interfaceAddr.s_addr;
1536 ret = sendto(netPath->eventSock, buf, length, 0,
1537 (struct sockaddr *)&addr,
1538 sizeof(struct sockaddr_in));
1539 if (ret <= 0)
1540 DBG("Error looping back unicast event message\n");
1541 }
1542 #endif /* SO_TIMESTAMPING */
1543 } else {
1544 addr.sin_addr.s_addr = netPath->multicastAddr;
1545 /* Is TTL OK? */
1546 if(netPath->ttlEvent != rtOpts->ttl) {
1547 /* Try restoring TTL */
1548 /* set socket time-to-live */
1549 if (netSetMulticastTTL(netPath->eventSock,rtOpts->ttl)) {
1550 netPath->ttlEvent = rtOpts->ttl;
1551 }
1552 }
1553 ret = sendto(netPath->eventSock, buf, length, 0,
1554 (struct sockaddr *)&addr,
1555 sizeof(struct sockaddr_in));
1556 if (ret <= 0)
1557 DBG("Error sending multicast event message\n");
1558 else
1559 netPath->sentPackets++;
1560 #ifdef SO_TIMESTAMPING
1561 if(!netPath->txTimestampFailure) {
1562 if(!getTxTimestamp(netPath, tim)) {
1563 if (tim) {
1564 clearTime(tim);
1565 }
1566
1567 netPath->txTimestampFailure = TRUE;
1568
1569 /* Try re-enabling MULTICAST_LOOP */
1570 netSetMulticastLoopback(netPath, TRUE);
1571 }
1572 }
1573 #endif /* SO_TIMESTAMPING */
1574 }
1575
1576 #ifdef PTPD_PCAP
1577 }
1578 #endif
1579 return ret;
1580 }
1581
1582 ssize_t
1583 netSendGeneral(Octet * buf, UInteger16 length, NetPath * netPath,
1584 RunTimeOpts *rtOpts, Integer32 alt_dst)
1585 {
1586 ssize_t ret;
1587 struct sockaddr_in addr;
1588
1589 addr.sin_family = AF_INET;
1590 addr.sin_port = htons(PTP_GENERAL_PORT);
1591
1592 #ifdef PTPD_PCAP
1593 if ((netPath->pcapGeneral != NULL) && (rtOpts->transport == IEEE_802_3)) {
1594 ret = netSendPcapEther(buf, length,
1595 &netPath->etherDest,
1596 (struct ether_addr *)netPath->interfaceID,
1597 netPath->pcapGeneral);
1598
1599 if (ret <= 0)
1600 DBG("Error sending ether multicast general message\n");
1601 else
1602 netPath->sentPackets++;
1603 } else {
1604 #endif
1605 if(netPath->unicastAddr || alt_dst ){
1606 if (netPath->unicastAddr) {
1607 addr.sin_addr.s_addr = netPath->unicastAddr;
1608 } else {
1609 addr.sin_addr.s_addr = alt_dst;
1610 }
1611
1612 /*
1613 * This function is used for PTP only anyway...
1614 * If we're sending to a unicast address, set the UNICAST flag.
1615 */
1616 *(char *)(buf + 6) |= PTP_UNICAST;
1617
1618 ret = sendto(netPath->generalSock, buf, length, 0,
1619 (struct sockaddr *)&addr,
1620 sizeof(struct sockaddr_in));
1621 if (ret <= 0)
1622 DBG("Error sending unicast general message\n");
1623 else
1624 netPath->sentPackets++;
1625 } else {
1626 addr.sin_addr.s_addr = netPath->multicastAddr;
1627
1628 /* Is TTL OK? */
1629 if(netPath->ttlGeneral != rtOpts->ttl) {
1630 /* Try restoring TTL */
1631 if (netSetMulticastTTL(netPath->generalSock,rtOpts->ttl)) {
1632 netPath->ttlGeneral = rtOpts->ttl;
1633 }
1634 }
1635
1636 ret = sendto(netPath->generalSock, buf, length, 0,
1637 (struct sockaddr *)&addr,
1638 sizeof(struct sockaddr_in));
1639 if (ret <= 0)
1640 DBG("Error sending multicast general message\n");
1641 else
1642 netPath->sentPackets++;
1643 }
1644
1645 #ifdef PTPD_PCAP
1646 }
1647 #endif
1648 return ret;
1649 }
1650
1651 ssize_t
1652 netSendPeerGeneral(Octet * buf, UInteger16 length, NetPath * netPath, RunTimeOpts *rtOpts)
1653 {
1654
1655 ssize_t ret;
1656 struct sockaddr_in addr;
1657
1658 addr.sin_family = AF_INET;
1659 addr.sin_port = htons(PTP_GENERAL_PORT);
1660
1661 #ifdef PTPD_PCAP
1662 if ((netPath->pcapGeneral != NULL) && (rtOpts->transport == IEEE_802_3)) {
1663 ret = netSendPcapEther(buf, length,
1664 &netPath->peerEtherDest,
1665 (struct ether_addr *)netPath->interfaceID,
1666 netPath->pcapGeneral);
1667
1668 if (ret <= 0)
1669 DBG("error sending ether multi-cast general message\n");
1670 } else if (netPath->unicastAddr)
1671 #else
1672 if (netPath->unicastAddr)
1673 #endif
1674 {
1675 addr.sin_addr.s_addr = netPath->unicastAddr;
1676
1677 ret = sendto(netPath->generalSock, buf, length, 0,
1678 (struct sockaddr *)&addr,
1679 sizeof(struct sockaddr_in));
1680 if (ret <= 0)
1681 DBG("Error sending unicast peer general message\n");
1682
1683 } else {
1684 addr.sin_addr.s_addr = netPath->peerMulticastAddr;
1685
1686 /* is TTL already 1 ? */
1687 if(netPath->ttlGeneral != 1) {
1688 /* Try setting TTL to 1 */
1689 if (netSetMulticastTTL(netPath->generalSock,1)) {
1690 netPath->ttlGeneral = 1;
1691 }
1692 }
1693 ret = sendto(netPath->generalSock, buf, length, 0,
1694 (struct sockaddr *)&addr,
1695 sizeof(struct sockaddr_in));
1696 if (ret <= 0)
1697 DBG("Error sending multicast peer general message\n");
1698 }
1699
1700 if (ret > 0)
1701 netPath->sentPackets++;
1702
1703 return ret;
1704
1705 }
1706
1707 ssize_t
1708 netSendPeerEvent(Octet * buf, UInteger16 length, NetPath * netPath, RunTimeOpts *rtOpts, TimeInternal * tim)
1709 {
1710 ssize_t ret;
1711 struct sockaddr_in addr;
1712
1713 addr.sin_family = AF_INET;
1714 addr.sin_port = htons(PTP_EVENT_PORT);
1715
1716 #ifdef PTPD_PCAP
1717 if ((netPath->pcapGeneral != NULL) && (rtOpts->transport == IEEE_802_3)) {
1718 ret = netSendPcapEther(buf, length,
1719 &netPath->peerEtherDest,
1720 (struct ether_addr *)netPath->interfaceID,
1721 netPath->pcapGeneral);
1722
1723 if (ret <= 0)
1724 DBG("error sending ether multi-cast general message\n");
1725 } else if (netPath->unicastAddr)
1726 #else
1727 if (netPath->unicastAddr)
1728 #endif
1729 {
1730 addr.sin_addr.s_addr = netPath->unicastAddr;
1731
1732 ret = sendto(netPath->eventSock, buf, length, 0,
1733 (struct sockaddr *)&addr,
1734 sizeof(struct sockaddr_in));
1735 if (ret <= 0)
1736 DBG("Error sending unicast peer event message\n");
1737 else
1738 netPath->sentPackets++;
1739
1740 #ifndef SO_TIMESTAMPING
1741 /*
1742 * Need to forcibly loop back the packet since
1743 * we are not using multicast.
1744 */
1745 addr.sin_addr.s_addr = netPath->interfaceAddr.s_addr;
1746
1747 ret = sendto(netPath->eventSock, buf, length, 0,
1748 (struct sockaddr *)&addr,
1749 sizeof(struct sockaddr_in));
1750 if (ret <= 0)
1751 DBG("Error looping back unicast peer event message\n");
1752 #else
1753 if(!netPath->txTimestampFailure) {
1754 if(!getTxTimestamp(netPath, tim)) {
1755 netPath->txTimestampFailure = TRUE;
1756 if (tim) {
1757 clearTime(tim);
1758 }
1759 }
1760 }
1761
1762 if(netPath->txTimestampFailure) {
1763 /* We've had a TX timestamp receipt timeout - falling back to packet looping */
1764 addr.sin_addr.s_addr = netPath->interfaceAddr.s_addr;
1765 ret = sendto(netPath->eventSock, buf, length, 0,
1766 (struct sockaddr *)&addr,
1767 sizeof(struct sockaddr_in));
1768 if (ret <= 0)
1769 DBG("Error looping back unicast event message\n");
1770 }
1771 #endif /* SO_TIMESTAMPING */
1772
1773 } else {
1774 addr.sin_addr.s_addr = netPath->peerMulticastAddr;
1775
1776 /* is TTL already 1 ? */
1777 if(netPath->ttlEvent != 1) {
1778 /* Try setting TTL to 1 */
1779 if (netSetMulticastTTL(netPath->eventSock,1)) {
1780 netPath->ttlEvent = 1;
1781 }
1782 }
1783 ret = sendto(netPath->eventSock, buf, length, 0,
1784 (struct sockaddr *)&addr,
1785 sizeof(struct sockaddr_in));
1786 if (ret <= 0)
1787 DBG("Error sending multicast peer event message\n");
1788 else
1789 netPath->sentPackets++;
1790 #ifdef SO_TIMESTAMPING
1791 if(!netPath->txTimestampFailure) {
1792 if(!getTxTimestamp(netPath, tim)) {
1793 if (tim) {
1794 clearTime(tim);
1795 }
1796
1797 netPath->txTimestampFailure = TRUE;
1798
1799 /* Try re-enabling MULTICAST_LOOP */
1800 netSetMulticastLoopback(netPath, TRUE);
1801 }
1802 }
1803 #endif /* SO_TIMESTAMPING */
1804 }
1805
1806 if (ret > 0)
1807 netPath->sentPackets++;
1808
1809 return ret;
1810 }
1811
1812
1813
1814 /*
1815 * refresh IGMP on a timeout
1816 */
1817 /*
1818 * @return TRUE if successful
1819 */
1820 Boolean
1821 netRefreshIGMP(NetPath * netPath, RunTimeOpts * rtOpts, PtpClock * ptpClock)
1822 {
1823 DBG("netRefreshIGMP\n");
1824
1825 netShutdownMulticast(netPath);
1826
1827 /* suspend process 100 milliseconds, to make sure the kernel sends the IGMP_leave properly */
1828 usleep(100*1000);
1829
1830 if (!netInitMulticast(netPath, rtOpts)) {
1831 return FALSE;
1832 }
1833 return TRUE;
1834 }