Exemplo n.º 1
0
/*-------------------------------------------------------------------------
 * mon_bootp_parse -
 *-------------------------------------------------------------------------
 */
int mon_bootp_parse(struct bootp_msg *p)
{
    
    unsigned long cookie;

    cookie = *(unsigned long *)p->vend;
    if (net2hl(cookie) != RFC1084) {
#ifdef PRINTERR
        kprintf("Incorrect RFC 1084 magic cookie in BOOTP reply.\n");
#endif
        return SYSERR;
    }

    /* grab my IP addr */
    mon_eth_pni->ni_ip = p->yiaddr;
    
    /* boot server IP */
    mon_tftp_server = p->siaddr;
    
    /* boot file name */
    strcpy(mon_boot_fname, p->file);

#ifdef DEBUG
    kprintf("my IP addr is %x.\n", net2hl(mon_eth_pni->ni_ip));
    kprintf("Boot file: %s, server: %x.\n", mon_boot_fname,
	    net2hl(mon_tftp_server));
#endif

    return(OK);
}
Exemplo n.º 2
0
/*------------------------------------------------------------------------
 * getutim  --  obtain time in seconds past Jan 1, 1970, ut (gmt)
 *------------------------------------------------------------------------
 */
SYSCALL
getutim(unsigned long *timvar)
{
	int	dev;
	int	len;
	int	ret;
	u_long	now;
	u_long	utnow;
	char	*msg = "No time server response\n";

	wait(clmutex);
	ret = OK;
	if (clktime < SECPERHR) {	/* assume small numbers invalid	*/
		if ((dev=open(UDP, TSERVER, ANYLPORT)) == SYSERR ||
		    control(dev,DG_SETMODE,DG_TMODE|DG_DMODE) == SYSERR) {
			panic(msg);
			ret = SYSERR;
		}
		write(dev, msg, 2);	/* send junk packet to prompt */
		if (read(dev,&utnow,4) != 4) {
			ret = SYSERR;
		} else
			clktime = net2xt( net2hl(utnow) );
		close(dev);
	}
	*timvar = clktime;
	signal(clmutex);
	return(ret);
}
Exemplo n.º 3
0
/*------------------------------------------------------------------------
 *  tcpsmss - set sender MSS from option in incoming segment
 *------------------------------------------------------------------------
 */
int
tcpsmss(struct tcb *ptcb, struct tcp *ptcp, u_char *popt)
{
	unsigned	mss, len;

	len = *++popt;
	++popt;		/* skip length field */
	if ((ptcp->tcp_code & TCPF_SYN) == 0)
		return len;
	switch (len-2) {	/* subtract kind & len	*/
	case sizeof(char):
		mss = *popt;
		break;
	case sizeof(short):
		mss = net2hs(*(unsigned short *)popt);
		break;
	case sizeof(long):
		mss = net2hl(*(unsigned long *)popt);
		break;
	default:
		mss = ptcb->tcb_smss;
		break;
	}
	mss -= TCPMHLEN;	/* save just the data buffer size */
	if (ptcb->tcb_smss)
		ptcb->tcb_smss = min(mss, ptcb->tcb_smss);
	else
		ptcb->tcb_smss = mss;
	return len;
}
Exemplo n.º 4
0
/**
 * Return elapsed trip time in microseconds.
 */
static ulong echoTripTime(struct packet *pkt)
{
    struct icmpPkt *icmp = NULL;
    struct icmpEcho *echo = NULL;
    ulong elapsed = 0, cycPerTick = 0;

    icmp = (struct icmpPkt *)pkt->curr;
    echo = (struct icmpEcho *)icmp->data;

    cycPerTick = platform.clkfreq / CLKTICKS_PER_SEC;

    elapsed = (echo->arrivcyc - net2hl(echo->timecyc)) % cycPerTick;
    elapsed += (echo->arrivtic - net2hl(echo->timetic)) * cycPerTick;
    elapsed +=
        (echo->arrivsec - net2hl(echo->timesec)) * platform.clkfreq;
    elapsed = elapsed / (platform.clkfreq / 1000000);
    return elapsed;
}
Exemplo n.º 5
0
/*------------------------------------------------------------------------
 *  rwhoind  -  rwho daemon to record info from incoming rwho packets
 *------------------------------------------------------------------------
 */
PROCESS
rwhoind(void)
{
	STATWORD ps;    
	int	dev;
	int	len;
	int	i;
	u_long	now;
	struct	rwhopac	*rpacptr;
	struct	rwent	*rwptr;

	if ( (dev=open(UDP, ANYFPORT, (void *)UP_RWHO)) == SYSERR ||
	      control(dev, DG_SETMODE, DG_DMODE) == SYSERR)
		panic("rwho_in: cannot open rwho port");
	while (TRUE) {
		if ( (len = read(dev,Rwho.rbuf,RWMAXP)) == SYSERR )
			continue;
		rpacptr = (struct rwhopac *) Rwho.rbuf;
		rpacptr->rw_host[RMACLEN-1] = '\00';
		for (i=0 ; i<Rwho.rwnent ; i++) {
			rwptr = &Rwho.rwcache[i];
			if (strncmp(rpacptr->rw_host, rwptr->rwmach,
			    RMACLEN) == 0)
				break;
		}
		if (i >= Rwho.rwnent) {
			disable(ps);
			if (Rwho.rwnent >= RWCSIZ) {
				restore(ps);
				continue;
			}
			rwptr = &Rwho.rwcache[Rwho.rwnent++];
			strncpy(rwptr->rwmach, rpacptr->rw_host, RMACLEN);
			restore(ps);
		}
		rwptr->rwboot = net2hl(rpacptr->rw_btim);
		gettime(&now);
		rwptr->rwlast = now;
		rwptr->rwslast = net2hl(rpacptr->rw_sndtim);
		for (i=0 ; i<RWNLOAD ; i++)
			rwptr->rwload[i] = net2hl(rpacptr->rw_load[i]);
		rwptr->rwusers = (len-RWMINP)/sizeof(struct rw_who);
	}
}
Exemplo n.º 6
0
/**
 * Send an ICMP Echo (Ping) Request.
 * @param dst destination address
 * @param id  ping stream identifier
 * @param seq sequence number
 * @return OK if packet was sent, otherwise SYSERR
 */
syscall icmpEchoRequest(struct netaddr *dst, ushort id, ushort seq)
{
    struct packet *pkt = NULL;
    struct icmpEcho *echo = NULL;
    int result = OK;
    irqmask im;

    ICMP_TRACE("echo request(%d, %d)", id, seq);
    pkt = netGetbuf();
    if (SYSERR == (int)pkt)
    {
        ICMP_TRACE("Failed to acquire packet buffer");
        return SYSERR;
    }

    pkt->len = sizeof(struct icmpEcho);
    pkt->curr -= pkt->len;

    echo = (struct icmpEcho *)pkt->curr;
    echo->id = hs2net(id);
    echo->seq = hs2net(seq);
    /* Our optional data payload includes room for the departure */
    /*  and arrival timestamps, in seconds, milliseconds, and    */
    /*  clock cycles.                                            */
    im = disable();
    echo->timecyc = hl2net(clkcount());
    echo->timetic = hl2net(clkticks);
    echo->timesec = hl2net(clktime);
    restore(im);
    echo->arrivcyc = 0;
    echo->arrivtic = 0;
    echo->arrivsec = 0;

    ICMP_TRACE("Sending Echo Request id = %d, seq = %d, time = %d.%d",
               net2hs(echo->id), net2hs(echo->seq),
               net2hl(echo->timesec), net2hl(echo->timetic));

    result = icmpSend(pkt, ICMP_ECHO, 0, sizeof(struct icmpEcho), dst);
    netFreebuf(pkt);
    return result;
}
Exemplo n.º 7
0
/*------------------------------------------------------------------------
 *  lsr_add - add a link state summary to a link state request packet
 *------------------------------------------------------------------------
 */
struct ep *
lsr_add(struct ospf_if *pif, struct ospf_lss *plss, struct ep *pep)
{
	struct ip	*pip;
	struct ospf	*po;
	struct ospf_lsr	*plsr;

	if (pep == 0) {
		pep = ospflsrtmpl(pif);
		if (pep == 0)
			return 0;
	}
	pip = (struct ip *)pep->ep_data;
	po = (struct ospf *)pip->ip_data;
	plsr = (struct ospf_lsr *)((char *)po + po->ospf_len);
	plsr->lsr_type = net2hl((unsigned long)plss->lss_type);
	plsr->lsr_lsid = plss->lss_lsid;
	plsr->lsr_rid = plss->lss_rid;
	po->ospf_len += LSRLEN;
	return pep;
}
Exemplo n.º 8
0
/**
 * The comments for dhcpRecvReply() apply, but for do_dhcpRecvReply() there is
 * no timeout and it is executed in a separate thread; furthermore, since this
 * thread can be killed at any time, it must use the memory passed in the @p pkt
 * parameter rather than allocating its own memory.
 */
static thread do_dhcpRecvReply(int descrp, struct dhcpData *data,
                               struct packet *pkt)
{
    const struct etherPkt *epkt;
    const struct ipv4Pkt *ipv4;
    const struct udpPkt *udp;
    const struct dhcpPkt *dhcp;
    const uchar *opts;
    uint maxlen;
    int found_msg;
    int retval;
    const uchar *gatewayptr;
    const uchar *maskptr;
    const uchar *opts_end;
    uint serverIpv4Addr;
    int mtu;
    int linkhdrlen;

    mtu = control(descrp, NET_GET_MTU, 0, 0);
    linkhdrlen = control(descrp, NET_GET_LINKHDRLEN, 0, 0);
    if (SYSERR == mtu || SYSERR == linkhdrlen)
    {
        return SYSERR;
    }

    maxlen = linkhdrlen + mtu;

    /* Receive packets until we find a response we're waiting for.  */

next_packet:
    do
    {
        /* Receive next packet from the network device.  */
        int len = read(descrp, pkt->data, maxlen);
        if (len == SYSERR || len <= 0)
        {
            data->recvStatus = SYSERR;
            return SYSERR;
        }

        pkt->len = len;
        DHCP_TRACE("Received packet (len=%u).", pkt->len);

        /* Make sure packet is at least the minimum length of a DHCP packet.  */
        if (pkt->len < (ETH_HDR_LEN + IPv4_HDR_LEN +
                        UDP_HDR_LEN + DHCP_HDR_LEN))
        {
            DHCP_TRACE("Too short to be a DHCP packet.");
            goto next_packet;
        }

        /* Set up header pointers  */
        epkt = (const struct etherPkt *)pkt->data;
        ipv4 = (const struct ipv4Pkt *)epkt->data;
        udp = (const struct udpPkt *)ipv4->opts;
        dhcp = (const struct dhcpPkt *)udp->data;

        /* DHCP packets must be type IPv4, protocol UDP, UDP dest port DHCPC,
         * and UDP source port DHCPS.
         *
         * Also check the DHCP header:  Is it actually a reply to this client?
         * */
        if ((ETHER_TYPE_IPv4 != net2hs(epkt->type))
            || (IPv4_PROTO_UDP != ipv4->proto)
            || (UDP_PORT_DHCPC != net2hs(udp->dstPort))
            || (UDP_PORT_DHCPS != net2hs(udp->srcPort))
            || (DHCP_OP_REPLY != dhcp->op)
            || (data->cxid != net2hl(dhcp->xid)))
        {
            DHCP_TRACE("Not a DHCP reply to this client.");
            goto next_packet;
        }

        DHCP_TRACE("Received DHCP reply.");

    #if DHCP_DROP_PACKET_PERCENT != 0
        /* Stress testing.  */
        if (rand() % 100 < DHCP_DROP_PACKET_PERCENT)
        {
            DHCP_TRACE("WARNING: Ignoring valid DHCP packet for test purposes.");
            goto next_packet;
        }
    #endif

        /* We got a valid DHCP reply.  Now parse the DHCP options.  This needs
         * to be done carefully to avoid overrunning the packet buffer if the
         * options data is invalid.  */
        opts = dhcp->opts;
        maskptr = NULL;
        gatewayptr = NULL;
        serverIpv4Addr = 0;
        opts_end = opts + (pkt->len - (ETH_HDR_LEN + IPv4_HDR_LEN +
                                       UDP_HDR_LEN + DHCP_HDR_LEN));
        found_msg = -1;
        for (;;)
        {
            uchar opt, len;

            /* Get the next option type.  */
            if (opts >= opts_end)
            {
                DHCP_TRACE("Invalid DHCP options.");
                goto next_packet;
            }
            opt = *opts++;

            /* Break on DHCP_OPT_END (marks end of DHCP options).  */
            if (DHCP_OPT_END == opt)
            {
                DHCP_TRACE("Reached DHCP_OPT_END.");
                break;
            }

            /* Get length of the data for this option.  */
            if (opts >= opts_end)
            {
                DHCP_TRACE("Invalid DHCP options.");
                goto next_packet;
            }
            len = *opts++;

            if (opts + len >= opts_end)
            {
                DHCP_TRACE("Invalid DHCP options.");
                goto next_packet;
            }

            /* Process the specific DHCP option.  Ignore unrecognized options.
             * */
            switch (opt)
            {
            case DHCP_OPT_MSGTYPE:
                DHCP_TRACE("DHCP_OPT_MSGTYPE: %d", *opts);
                if (len >= 1)
                {
                    if ((DHCPC_STATE_SELECTING == data->state &&
                         *opts == DHCPOFFER)
                        || (DHCPC_STATE_REQUESTING == data->state &&
                            (DHCPACK == *opts || DHCPNAK == *opts)))
                    {
                        found_msg = *opts;
                    }
                }
                break;

            case DHCP_OPT_SUBNET:
                if (len >= IPv4_ADDR_LEN)
                {
                    maskptr = opts;
                }
                break;

            case DHCP_OPT_GATEWAY:
                if (len >= IPv4_ADDR_LEN)
                {
                    gatewayptr = opts;
                }
                break;

            case DHCP_OPT_SERVER:
                if (len >= IPv4_ADDR_LEN)
                {
                    /* Server Identifier option.  */
                    serverIpv4Addr = ((uint)opts[0] << 24) |
                                     ((uint)opts[1] << 16) |
                                     ((uint)opts[2] << 8) |
                                     ((uint)opts[3] << 0);
                }
                break;
            }

            /* Advance by the length of the option's data.  */
            opts += len;
        }
    } while (found_msg < 0);

    /* We received a reply of at least the right type as one we were looking
     * for.  */

    /* Don't consider a DHCPACK reply to be valid unless it provided a subnet
     * mask.  */
    if (DHCPACK == found_msg && NULL == maskptr)
    {
        DHCP_TRACE("Ignoring DHCPACK (no subnet mask provided).");
        goto next_packet;
    }

    /* Note: The server's IP address is supposed to be specified in the Server
     * Identifier option, *not* in the siaddr (Server IP Address) field.  This
     * is because, somewhat unintuitively, siaddr is used for the address of the
     * next server in the bootstrap process, which may not be the same as the
     * DHCP server.  But if the Server Identifier option wasn't present, use
     * siaddr anyway.  */
    if (0 == serverIpv4Addr)
    {
        serverIpv4Addr = net2hl(dhcp->siaddr);
        if (0 == serverIpv4Addr)
        {
            DHCP_TRACE("Server IP address empty.");
            goto next_packet;
        }
    }

    if (DHCPOFFER == found_msg)
    {
        /* DHCPOFFER:  Remember offer and server addresses.  */
        data->serverIpv4Addr = serverIpv4Addr;
        data->offeredIpv4Addr = net2hl(dhcp->yiaddr);
        memcpy(data->serverHwAddr, epkt->src, ETH_ADDR_LEN);
        retval = OK;
    }
    else
    {
        /* Received DHCPACK or DHCPNAK.  Ensure it's from the same server to
         * which we sent the DHCPREQUEST; if not, ignore the packet.  */
        if (serverIpv4Addr != data->serverIpv4Addr)
        {
            DHCP_TRACE("Reply from wrong server.");
            goto next_packet;
        }

        if (DHCPNAK == found_msg)
        {
            /* DHCPNAK:  Return error to make client try DHCPDISCOVER again  */
            retval = SYSERR;
        }
        else
        {
            /* DHCPACK:  Set network interface addresses  */
            data->ip.type = NETADDR_IPv4;
            data->ip.len = IPv4_ADDR_LEN;
            /* yiaddr in a DHCPACK should be the same as the yiaddr stored from
             * the DHCPOFFER, but using the value in DHCPACK is preferable since
             * it's the value the server thinks it assigned.  */
            memcpy(data->ip.addr, &dhcp->yiaddr, IPv4_ADDR_LEN);
            data->clientIpv4Addr = net2hl(dhcp->yiaddr);

            data->mask.type = NETADDR_IPv4;
            data->mask.len = IPv4_ADDR_LEN;
            memcpy(data->mask.addr, maskptr, IPv4_ADDR_LEN);

            if (NULL != gatewayptr)
            {
                data->gateway.type = NETADDR_IPv4;
                data->gateway.len = IPv4_ADDR_LEN;
                memcpy(data->gateway.addr, gatewayptr, IPv4_ADDR_LEN);
            }

            /* If provided in the DHCPACK, set the address of next server and
             * the boot file (e.g. for TFTP).  */
            if (0 != dhcp->siaddr)
            {
                data->next_server.type = NETADDR_IPv4;
                data->next_server.len = IPv4_ADDR_LEN;
                memcpy(data->next_server.addr, &dhcp->siaddr, IPv4_ADDR_LEN);
            }
            if ('\0' != dhcp->file[0])
            {
                memcpy(data->bootfile, dhcp->file, sizeof(data->bootfile) - 1);
            }
        #ifdef ENABLE_DHCP_TRACE
            {
                char str_addr[24];
                netaddrsprintf(str_addr, &data->ip);
                DHCP_TRACE("Set ip=%s", str_addr);

                netaddrsprintf(str_addr, &data->mask);
                DHCP_TRACE("Set mask=%s", str_addr);

                if (NULL != gatewayptr)
                {
                    netaddrsprintf(str_addr, &data->gateway);
                    DHCP_TRACE("Set gateway=%s", str_addr);
                }
                else
                {
                    DHCP_TRACE("No gateway.");
                }

                netaddrsprintf(str_addr, &data->next_server);
                DHCP_TRACE("TFTP server=%s", str_addr);
                DHCP_TRACE("Bootfile=%s", data->bootfile);
            }
        #endif
            retval = OK;
        }
    }
    data->recvStatus = retval;
    return retval;
}
Exemplo n.º 9
0
/**
 * @ingroup snoop
 *
 * Print contents of an TCP packet
 * @param tcp TCP packet
 * @return OK if print successful, SYSERR if error occurs
 */
int snoopPrintTcp(struct tcpPkt *tcp, char verbose)
{
    char descrp[40];
    char output[40];

    /* Error check pointer */
    if (NULL == tcp)
    {
        return SYSERR;
    }

    if (verbose >= SNOOP_VERBOSE_ONE)
    {
        printf(" ----- TCP Header -----\n", "");
        /* Source Port */
        if (verbose >= SNOOP_VERBOSE_TWO)
        {
            snoopPrintTcpPort(net2hs(tcp->srcpt), descrp);
        }
        else
        {
            sprintf(descrp, "");
        }
        sprintf(output, "%d %s", net2hs(tcp->srcpt), descrp);
        printf("  Src Port: %-25s ", output);

        /* Destination Port */
        if (verbose >= SNOOP_VERBOSE_TWO)
        {
            snoopPrintTcpPort(net2hs(tcp->dstpt), descrp);
        }
        else
        {
            sprintf(descrp, "");
        }
        sprintf(output, "%d %s", net2hs(tcp->dstpt), descrp);
        printf("Dst Port: %-25s\n", output);

        /* Sequence number */
        printf("  Seq Num: %-14u ", net2hl(tcp->seqnum));
        /* Acknowledgement number */
        printf("Ack Num: %-14u ", net2hl(tcp->acknum));
        /* Control flags */
        printf("Ctrl: ");
        if (tcp->control & TCP_CTRL_URG)
        {
            printf("U ");
        }
        if (tcp->control & TCP_CTRL_ACK)
        {
            printf("A ");
        }
        if (tcp->control & TCP_CTRL_PSH)
        {
            printf("P ");
        }
        if (tcp->control & TCP_CTRL_RST)
        {
            printf("R ");
        }
        if (tcp->control & TCP_CTRL_SYN)
        {
            printf("S ");
        }
        if (tcp->control & TCP_CTRL_FIN)
        {
            printf("F ");
        }
        printf("\n");

        if (verbose >= SNOOP_VERBOSE_TWO)
        {
            sprintf(output, "%d bytes", offset2octets(tcp->offset));
            printf("  Offset: %-15s ", output);
            sprintf(output, "%d bytes", net2hs(tcp->window));
            printf("Window: %-15s ", output);
            printf("Chksum: 0x%04X\n", net2hs(tcp->chksum));
        }
    }

    return OK;
}
Exemplo n.º 10
0
/* ********************************************************************   */
int sntp_process_result(int socket_no, PNTP_TIME_FORMAT current_timestamp,
                        int version, dword ticks_when_sent,
                        PEBSTIME res_ebs_tod)

{
int             n_received;
NTP_PKT         ntp_response;
NTP_TIME_FORMAT temp_time1;
NTP_TIME_FORMAT temp_time2;
NTP_TIME_FORMAT t1;
NTP_TIME_FORMAT t2;
NTP_TIME_FORMAT t3;
NTP_TIME_FORMAT t4;
NTP_TIME_FORMAT local_offset;
NTP_TIME_FORMAT delay_time;         /* round trip delay */
#if (DELAY_TICKS)
dword           delay_ticks;
dword           curr_ticks;
#endif
RTIP_BOOLEAN    gmt_neg;

#if (DELAY_TICKS)
    curr_ticks = ks_get_ticks();
    if (CHECK_GREATER(curr_ticks, ticks_when_sent))
        delay_ticks = curr_ticks - ticks_when_sent;
    else
        delay_ticks = (int)( (long)((long)curr_ticks - 
                             (long)ticks_when_sent) );

#if (DEBUG_DELAY_TICKS)
    DEBUG_ERROR("ks_get_ticks, ticks_when_sent: ", DINT2,
        curr_ticks, ticks_when_sent);
#endif
#endif

    /* Get a packet   */
    n_received = recv(socket_no, (PFCHAR)&ntp_response, 
                      sizeof(ntp_response), 0);
    if (n_received < 0)
    {
        DEBUG_ERROR("sntp_process_result: recv failed", EBS_INT1, 
            xn_getlasterror(), 0);
    }

    closesocket(socket_no);

    /* verify response - mode   */
    if ( ((ntp_response.li_vn_mode & NTP_MODE_MASK) != NTP_SYM_PASSIVE) &&
         ((ntp_response.li_vn_mode & NTP_MODE_MASK) != NTP_RESPONSE) )
    {
        DEBUG_ERROR("sntp_process_result: response invalid: exp, act", 
            EBS_INT2, 
            NTP_SYM_PASSIVE, ntp_response.li_vn_mode & NTP_MODE_MASK);
        return(-1);
    }

    /* verify response - stratum   */
    if ( (ntp_response.stratum < 1) || (ntp_response.stratum > 14) )
    {
        DEBUG_ERROR("sntp_process_result: stratum invalid: ", EBS_INT1,
            ntp_response.stratum, 0);
        return(-1);
    }

    /* verify response - version   */
    if ( (ntp_response.li_vn_mode & NTP_VERSION_MASK) != version )
    {
        DEBUG_ERROR("sntp_process_result: response invalid - version : exp, act", 
            EBS_INT2, version, 
            ntp_response.li_vn_mode & NTP_VERSION_MASK);
        return(-1);
    }

    ntp_response.rcv_timestamp.seconds = 
        net2hl(ntp_response.rcv_timestamp.seconds);

    ntp_response.ref_timestamp.seconds = 
        net2hl(ntp_response.ref_timestamp.seconds);

    ntp_response.transmit_timestamp.seconds = 
        net2hl(ntp_response.transmit_timestamp.seconds);

    /* seconds since Jan 1, 1970                  */
/*  DEBUG_ERROR("TIME SECONDS: seconds: ", DINT2, */
/*      ntp_response.rcv_timestamp.seconds,       */
/*      ntp_response.rcv_timestamp.frac_sec);     */

#if (DISPLAY_RCV_TIME)
    DEBUG_ERROR("\n***** RCV TIME *****", NOVAR, 0, 0);
    display_sntp_time(ntp_response.rcv_timestamp.seconds);
#endif

#if (DISPLAY_INT_TIMES)
/*  DEBUG_ERROR("***** REF TIME *****", NOVAR, 0, 0);      */
/*  display_sntp_time(ntp_response.ref_timestamp.seconds); */


/*  DEBUG_ERROR("***** TRANSMIT TIME *****", NOVAR, 0, 0);      */
/*  display_sntp_time(ntp_response.transmit_timestamp.seconds); */
#endif

#if (DELAY_TICKS)
    t4.seconds = delay_ticks / ks_ticks_p_sec();
    t4.frac_sec = 0;    /* tbd */
    DEBUG_ERROR("delay_ticks, t4.sec", DINT2, delay_ticks, t4.seconds);
#endif

    /* set the following                    */
    /* t2 = time request received by server */
    /* t3 = time reply sent by server       */
    /* t4 = time reply received by client   */
    STRUCT_COPY(t1, *current_timestamp); 
    STRUCT_COPY(t2, ntp_response.rcv_timestamp);
    STRUCT_COPY(t3, ntp_response.transmit_timestamp);
#if (!DELAY_TICKS)
    STRUCT_COPY(t4, *current_timestamp);
#endif

    /* set time response took to arrive from time sent   */
    /* delay_time = (t4-t1) - (t2-t3)                    */
    time_sub(&temp_time1, &t4, &t1);
    time_sub(&temp_time2, &t2, &t3);
    time_sub(&delay_time, &temp_time1, &temp_time2);

    /* calculate local time offset   */
    /* local clock offset            */
    time_sub(&temp_time1, &t2, &t1);
    time_sub(&temp_time2, &t3, &t4);
    time_add(&local_offset, &temp_time1, &temp_time2);
    time_div_2(&local_offset);

#if (DISPLAY_DELAY_OFFSET)
    display_total_time("\nDELAY TIME: ", delay_time.seconds);
    display_total_time("OFFSET TIME: ",  local_offset.seconds);
#endif

    gmt_neg = FALSE;
#if (!ADD_OFFSET)
    if (CFG_GMT_DIFF < 0)
    {
        gmt_neg = TRUE;
        /* convert hours to seconds, hence multiply by 3600;   */
        /* make it positive and it will be subtracted below    */
        local_offset.seconds = -(CFG_GMT_DIFF * SEC_PER_HOUR);
    }
    else
    {
        /* CFG_GMT_DIFF is positive so seconds is always positive   */
        local_offset.seconds = (dword)(CFG_GMT_DIFF * SEC_PER_HOUR);
    }
#endif
    local_offset.frac_sec = 0;

    /* update time with delay   */
    time_add(&temp_time1, &t3, &delay_time);

    /* save current time for next request   */
    STRUCT_COPY(*current_timestamp, temp_time1); 

    /* update time with time zone   */
    if (gmt_neg)
        time_sub(&temp_time2, &temp_time1, &local_offset);
    else
        time_add(&temp_time2, &temp_time1, &local_offset);


/*  display_total_time("BEFORE CONVERSION TO ebs_tod ", temp_time2.seconds);   */
/*  display_total_time("FINAL TIME ", temp_time2.seconds);                     */

    /* convert time returned by SNTP server to RTIP internal format   */
    convert_time_to_ebs_time(temp_time2.seconds, res_ebs_tod);

    return(0);
}