Example #1
0
File: net.c Project: DomChey/ptpd
/**
 * Init all network transports
 *
 * @param netPath 
 * @param rtOpts 
 * @param ptpClock 
 * 
 * @return TRUE if successful
 */
Boolean 
netInit(NetPath * netPath, RunTimeOpts * rtOpts, PtpClock * ptpClock)
{
	int temp;
	struct sockaddr_in addr;

#ifdef PTPD_PCAP
	struct bpf_program program;
	char errbuf[PCAP_ERRBUF_SIZE];
#endif

	DBG("netInit\n");

#ifdef PTPD_PCAP
	netPath->pcapEvent = NULL;
	netPath->pcapGeneral = NULL;
	netPath->pcapEventSock = -1;
	netPath->pcapGeneralSock = -1;
#endif
	netPath->generalSock = -1;
	netPath->eventSock = -1;

#ifdef PTPD_PCAP
	if (rtOpts->transport == IEEE_802_3) {
		netPath->headerOffset = PACKET_BEGIN_ETHER;
#ifdef HAVE_STRUCT_ETHER_ADDR_OCTET
		memcpy(netPath->etherDest.octet, ether_aton(PTP_ETHER_DST), ETHER_ADDR_LEN);
		memcpy(netPath->peerEtherDest.octet, ether_aton(PTP_ETHER_PEER), ETHER_ADDR_LEN);
#else
		memcpy(netPath->etherDest.ether_addr_octet, ether_aton(PTP_ETHER_DST), ETHER_ADDR_LEN);
		memcpy(netPath->peerEtherDest.ether_addr_octet, ether_aton(PTP_ETHER_PEER), ETHER_ADDR_LEN);
#endif /* HAVE_STRUCT_ETHER_ADDR_OCTET */
	} else
#endif
		netPath->headerOffset = PACKET_BEGIN_UDP;

	/* open sockets */
	if ((netPath->eventSock = socket(PF_INET, SOCK_DGRAM, 
					 IPPROTO_UDP)) < 0
	    || (netPath->generalSock = socket(PF_INET, SOCK_DGRAM, 
					      IPPROTO_UDP)) < 0) {
		PERROR("failed to initialize sockets");
		return FALSE;
	}

	if(!testInterface(rtOpts->ifaceName, rtOpts))
		return FALSE;

	netPath->interfaceInfo.addressFamily = AF_INET;

	/* the if is here only to get rid of an unused result warning. */
	if( getInterfaceInfo(rtOpts->ifaceName, &netPath->interfaceInfo)!= 1)
		return FALSE;

	/* No HW address, we'll use the protocol address to form interfaceID -> clockID */
	if( !netPath->interfaceInfo.hasHwAddress && netPath->interfaceInfo.hasAfAddress ) {
		uint32_t addr = netPath->interfaceInfo.afAddress.s_addr;
		memcpy(netPath->interfaceID, &addr, 2);
		memcpy(netPath->interfaceID + 4, &addr + 2, 2);
	/* Initialise interfaceID with hardware address */
	} else {
		    memcpy(&netPath->interfaceID, &netPath->interfaceInfo.hwAddress, 
			    sizeof(netPath->interfaceID) <= sizeof(netPath->interfaceInfo.hwAddress) ?
				    sizeof(netPath->interfaceID) : sizeof(netPath->interfaceInfo.hwAddress)
			    );
	}

	DBG("Listening on IP: %s\n",inet_ntoa(netPath->interfaceInfo.afAddress));

#ifdef PTPD_PCAP
	if (rtOpts->pcap == TRUE) {
		int promisc = (rtOpts->transport == IEEE_802_3 ) ? 1 : 0;
		if ((netPath->pcapEvent = pcap_open_live(rtOpts->ifaceName,
							 PACKET_SIZE, promisc,
							 PCAP_TIMEOUT,
							 errbuf)) == NULL) {
			PERROR("failed to open event pcap");
			return FALSE;
		}
		if (pcap_compile(netPath->pcapEvent, &program, 
				 ( rtOpts->transport == IEEE_802_3 ) ?
				    "ether proto 0x88f7":
				 ( rtOpts->ip_mode != IPMODE_MULTICAST ) ?
					 "udp port 319" :
				 "host (224.0.1.129 or 224.0.0.107) and udp port 319" ,
				 1, 0) < 0) {
			PERROR("failed to compile pcap event filter");
			pcap_perror(netPath->pcapEvent, "ptpd2");
			return FALSE;
		}
		if (pcap_setfilter(netPath->pcapEvent, &program) < 0) {
			PERROR("failed to set pcap event filter");
			return FALSE;
		}
		pcap_freecode(&program);
		if ((netPath->pcapEventSock = 
		     pcap_get_selectable_fd(netPath->pcapEvent)) < 0) {
			PERROR("failed to get pcap event fd");
			return FALSE;
		}		
		if ((netPath->pcapGeneral = pcap_open_live(rtOpts->ifaceName,
							   PACKET_SIZE, promisc,
							   PCAP_TIMEOUT,
							 errbuf)) == NULL) {
			PERROR("failed to open general pcap");
			return FALSE;
		}
		if (rtOpts->transport != IEEE_802_3) {
			if (pcap_compile(netPath->pcapGeneral, &program,
					 ( rtOpts->ip_mode != IPMODE_MULTICAST ) ?
						 "udp port 320" :
					 "host (224.0.1.129 or 224.0.0.107) and udp port 320" ,
					 1, 0) < 0) {
				PERROR("failed to compile pcap general filter");
				pcap_perror(netPath->pcapGeneral, "ptpd2");
				return FALSE;
			}
			if (pcap_setfilter(netPath->pcapGeneral, &program) < 0) {
				PERROR("failed to set pcap general filter");
				return FALSE;
			}
			pcap_freecode(&program);
			if ((netPath->pcapGeneralSock = 
			     pcap_get_selectable_fd(netPath->pcapGeneral)) < 0) {
				PERROR("failed to get pcap general fd");
				return FALSE;
			}
		}
	}
#endif

#ifdef PTPD_PCAP
	if(rtOpts->transport == IEEE_802_3) {
		close(netPath->eventSock);
		netPath->eventSock = -1;
		close(netPath->generalSock);
		netPath->generalSock = -1;
		/* TX timestamp is not generated for PCAP mode and Ethernet transport */
#ifdef SO_TIMESTAMPING
		netPath->txTimestampFailure = TRUE;
#endif /* SO_TIMESTAMPING */
	} else {
#endif
		/* save interface address for IGMP refresh */
		netPath->interfaceAddr = netPath->interfaceInfo.afAddress;

		DBG("Local IP address used : %s \n", inet_ntoa(netPath->interfaceInfo.afAddress));

		temp = 1;			/* allow address reuse */
		if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_REUSEADDR, 
			       &temp, sizeof(int)) < 0
		    || setsockopt(netPath->generalSock, SOL_SOCKET, SO_REUSEADDR, 
				  &temp, sizeof(int)) < 0) {
			DBG("failed to set socket reuse\n");
		}
		/* bind sockets */
		/*
		 * need INADDR_ANY to allow receipt of multi-cast and uni-cast
		 * messages
		 */

		/* why??? */
		if (rtOpts->pidAsClockId) {
			if (inet_pton(AF_INET, DEFAULT_PTP_DOMAIN_ADDRESS, &addr.sin_addr) < 0) {
				PERROR("failed to convert address");
				return FALSE;
			}
		} else
			addr.sin_addr.s_addr = htonl(INADDR_ANY);

		addr.sin_family = AF_INET;
		addr.sin_port = htons(PTP_EVENT_PORT);
		if (bind(netPath->eventSock, (struct sockaddr *)&addr, 
			sizeof(struct sockaddr_in)) < 0) {
			PERROR("failed to bind event socket");
			return FALSE;
		}
		addr.sin_port = htons(PTP_GENERAL_PORT);
		if (bind(netPath->generalSock, (struct sockaddr *)&addr, 
			sizeof(struct sockaddr_in)) < 0) {
			PERROR("failed to bind general socket");
			return FALSE;
		}

#ifdef USE_BINDTODEVICE
#ifdef linux
		/*
		 * The following code makes sure that the data is only
		 * received on the specified interface.  Without this option,
		 * it's possible to receive PTP from another interface, and
		 * confuse the protocol.  Calling bind() with the IP address
		 * of the device instead of INADDR_ANY does not work.
		 *
		 * More info:
		 *   http://developerweb.net/viewtopic.php?id=6471
		 *   http://stackoverflow.com/questions/1207746/problems-with-so-bindtodevice-linux-socket-option
		 */

		if ( rtOpts->ip_mode != IPMODE_HYBRID )
		if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_BINDTODEVICE,
				rtOpts->ifaceName, strlen(rtOpts->ifaceName)) < 0
			|| setsockopt(netPath->generalSock, SOL_SOCKET, SO_BINDTODEVICE,
				rtOpts->ifaceName, strlen(rtOpts->ifaceName)) < 0){
			PERROR("failed to call SO_BINDTODEVICE on the interface");
			return FALSE;
		}
#endif
#endif

		/* Set socket dscp */
		if(rtOpts->dscpValue) {

			if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_TOS,
				 &rtOpts->dscpValue, sizeof(int)) < 0
			    || setsockopt(netPath->generalSock, IPPROTO_IP, IP_TOS,
				&rtOpts->dscpValue, sizeof(int)) < 0) {
				    PERROR("Failed to set socket DSCP bits");
				    return FALSE;
				}
		}

		/* send a uni-cast address if specified (useful for testing) */
		if(!hostLookup(rtOpts->unicastAddress, &netPath->unicastAddr)) {
	                netPath->unicastAddr = 0;
		}


		if(rtOpts->ip_mode != IPMODE_UNICAST)  {

			/* init UDP Multicast on both Default and Peer addresses */
			if (!netInitMulticast(netPath, rtOpts))
				return FALSE;

			/* set socket time-to-live  */
			if(!netSetMulticastTTL(netPath->eventSock,rtOpts->ttl) ||
			    !netSetMulticastTTL(netPath->generalSock,rtOpts->ttl))
				return FALSE;

			/* start tracking TTL */
			netPath->ttlEvent = rtOpts->ttl;
			netPath->ttlGeneral = rtOpts->ttl;
		}

#ifdef SO_TIMESTAMPING
			/* Reset the failure indicator when (re)starting network */
			netPath->txTimestampFailure = FALSE;
			/* for SO_TIMESTAMPING we're receiving transmitted packets via ERRQUEUE */
			temp = 0;
#else
			/* enable loopback */
			temp = 1;
#endif

		/* make timestamps available through recvmsg() */
		if (!netInitTimestamping(netPath,rtOpts)) {
			ERROR("Failed to enable packet time stamping\n");
			return FALSE;
		}

#ifdef SO_TIMESTAMPING
		/* If we failed to initialise SO_TIMESTAMPING, enable mcast loopback */
		if(netPath->txTimestampFailure)
			temp = 1;
#endif

			if(!netSetMulticastLoopback(netPath, temp)) {
				return FALSE;
			}

#ifdef PTPD_PCAP
	}
#endif

	/* Compile ACLs */
	if(rtOpts->timingAclEnabled) {
    		freeIpv4AccessList(&netPath->timingAcl);
		netPath->timingAcl=createIpv4AccessList(rtOpts->timingAclPermitText,
			rtOpts->timingAclDenyText, rtOpts->timingAclOrder);
	}
	if(rtOpts->managementAclEnabled) {
		freeIpv4AccessList(&netPath->managementAcl);
		netPath->managementAcl=createIpv4AccessList(rtOpts->managementAclPermitText,
			rtOpts->managementAclDenyText, rtOpts->managementAclOrder);
	}

	return TRUE;
}
Example #2
0
void
restartSubsystems(RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
			DBG("RestartSubsystems: %d\n",rtOpts->restartSubsystems);
		    /* So far, PTP_INITIALIZING is required for both network and protocol restart */
		    if((rtOpts->restartSubsystems & PTPD_RESTART_PROTOCOL) ||
			(rtOpts->restartSubsystems & PTPD_RESTART_NETWORK)) {

			    if(rtOpts->restartSubsystems & PTPD_RESTART_NETWORK) {
				NOTIFY("Applying network configuration: going into PTP_INITIALIZING\n");
			    }

			    /* These parameters have to be passed to ptpClock before re-init */
			    ptpClock->clockQuality.clockClass = rtOpts->clockQuality.clockClass;
			    ptpClock->slaveOnly = rtOpts->slaveOnly;
			    ptpClock->disabled = rtOpts->portDisabled;

			    if(rtOpts->restartSubsystems & PTPD_RESTART_PROTOCOL) {
				INFO("Applying protocol configuration: going into %s\n",
				ptpClock->disabled ? "PTP_DISABLED" : "PTP_INITIALIZING");
			    }

			    /* Move back to primary interface only during configuration changes. */
			    ptpClock->runningBackupInterface = FALSE;
			    toState(ptpClock->disabled ? PTP_DISABLED : PTP_INITIALIZING, rtOpts, ptpClock);

		    } else {
		    /* Nothing happens here for now - SIGHUP handler does this anyway */
		    if(rtOpts->restartSubsystems & PTPD_UPDATE_DATASETS) {
				NOTIFY("Applying PTP engine configuration: updating datasets\n");
				updateDatasets(ptpClock, rtOpts);
		    }}
		    /* Nothing happens here for now - SIGHUP handler does this anyway */
		    if(rtOpts->restartSubsystems & PTPD_RESTART_LOGGING) {
				NOTIFY("Applying logging configuration: restarting logging\n");
		    }


    		if(rtOpts->restartSubsystems & PTPD_RESTART_ACLS) {
            		NOTIFY("Applying access control list configuration\n");
            		/* re-compile ACLs */
            		freeIpv4AccessList(&ptpClock->netPath.timingAcl);
            		freeIpv4AccessList(&ptpClock->netPath.managementAcl);
            		if(rtOpts->timingAclEnabled) {
                    	    ptpClock->netPath.timingAcl=createIpv4AccessList(rtOpts->timingAclPermitText,
                                rtOpts->timingAclDenyText, rtOpts->timingAclOrder);
            		}
            		if(rtOpts->managementAclEnabled) {
                    	    ptpClock->netPath.managementAcl=createIpv4AccessList(rtOpts->managementAclPermitText,
                                rtOpts->managementAclDenyText, rtOpts->managementAclOrder);
            		}
    		}


#ifdef PTPD_STATISTICS
                    /* Reinitialising the outlier filter containers */
                    if(rtOpts->restartSubsystems & PTPD_RESTART_FILTERS) {

                                NOTIFY("Applying filter configuration: re-initialising filters\n");

				freeDoubleMovingStatFilter(&ptpClock->filterMS);
				freeDoubleMovingStatFilter(&ptpClock->filterSM);

				ptpClock->oFilterMS.shutdown(&ptpClock->oFilterMS);
				ptpClock->oFilterSM.shutdown(&ptpClock->oFilterSM);

				outlierFilterSetup(&ptpClock->oFilterMS);
				outlierFilterSetup(&ptpClock->oFilterSM);

				ptpClock->oFilterMS.init(&ptpClock->oFilterMS,&rtOpts->oFilterMSConfig, "delayMS");
				ptpClock->oFilterSM.init(&ptpClock->oFilterSM,&rtOpts->oFilterSMConfig, "delaySM");


				if(rtOpts->filterMSOpts.enabled) {
					ptpClock->filterMS = createDoubleMovingStatFilter(&rtOpts->filterMSOpts,"delayMS");
				}

				if(rtOpts->filterSMOpts.enabled) {
					ptpClock->filterSM = createDoubleMovingStatFilter(&rtOpts->filterSMOpts, "delaySM");
				}

		    }
#endif /* PTPD_STATISTICS */

	    ptpClock->timingService.reloadRequested = TRUE;

            if(rtOpts->restartSubsystems & PTPD_RESTART_NTPENGINE && timingDomain.serviceCount > 1) {
		ptpClock->ntpControl.timingService.shutdown(&ptpClock->ntpControl.timingService);
	    }

	    if((rtOpts->restartSubsystems & PTPD_RESTART_NTPENGINE) ||
        	(rtOpts->restartSubsystems & PTPD_RESTART_NTPCONFIG)) {
        	ntpSetup(rtOpts, ptpClock);
    	    }
		if((rtOpts->restartSubsystems & PTPD_RESTART_NTPENGINE) && rtOpts->ntpOptions.enableEngine) {
		    timingServiceSetup(&ptpClock->ntpControl.timingService);
		    ptpClock->ntpControl.timingService.init(&ptpClock->ntpControl.timingService);
		}

		ptpClock->timingService.dataSet.priority1 = rtOpts->preferNTP;

		timingDomain.electionDelay = rtOpts->electionDelay;
		if(timingDomain.electionLeft > timingDomain.electionDelay) {
			timingDomain.electionLeft = timingDomain.electionDelay;
		}

		timingDomain.services[0]->holdTime = rtOpts->ntpOptions.failoverTimeout;

		if(timingDomain.services[0]->holdTimeLeft >
			timingDomain.services[0]->holdTime) {
			timingDomain.services[0]->holdTimeLeft =
			rtOpts->ntpOptions.failoverTimeout;
		}

		ptpClock->timingService.timeout = rtOpts->idleTimeout;

		    /* Update PI servo parameters */
		    setupPIservo(&ptpClock->servo, rtOpts);
		    /* Config changes don't require subsystem restarts - acknowledge it */
		    if(rtOpts->restartSubsystems == PTPD_RESTART_NONE) {
				NOTIFY("Applying configuration\n");
		    }

		    if(rtOpts->restartSubsystems != -1)
			    rtOpts->restartSubsystems = 0;

}