/*
 * Copyright (c) 1992 Purdue University
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by Purdue University.  The name of the University may not be used
 * to endorse or promote products derived * from this software without
 * specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Note: this copyright applies to portions of this software developed
 * at Purdue beyond the software covered by the original copyright.
 */

#include <time.h>
#include <fcntl.h>
#include <netdb.h>
#include <memory.h>
#include <string.h>

#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/param.h>
#include <sys/stream.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <sys/socket.h>
#include <sys/dlpi.h>

#include "dpio.h"
#include "dp.h"
#include "ppp.h"
#include "dpd.h"

char *sctime(),
     *port_str(),
     *cnts_str();

void
writelog(sitename, dev, starttime, stoptime, ds, dlu, req)
char *sitename, *dev;
time_t starttime, stoptime;
dp_stats_t *ds;
dl_unitdata_ind_t *dlu;
char *req;
{
    static char	WHERE[] = "writelog";
    int		f;
    long	hours;
    long	minutes;
    long	seconds;
    long	duration = stoptime - starttime;
    extern	char *ctime();
    char	lbuf[132+1], *l = lbuf;
    char	*cl;

    /* Just in case... */
    if (starttime == 0)
	return;

    hours = duration / 3600;
    minutes = (duration - hours * 3600) / 60;
    seconds = duration - hours * 3600 - minutes * 60;

    (void)sprintf(l, "%-12.12s%-6.6s %s %02ld:%02ld:%02ld %-7.7s ",
	sitename, dev, sctime(&starttime), hours, minutes, seconds, progname);
    l += strlen(l);

    (void)sprintf(l, "%-14s ", (dlu && req) ? port_str(dlu, req) : "");
    l += strlen(l);

    (void)sprintf(l, "I %-12s ",
		  cnts_str(ds->dps_ipackets, ds->dps_ibytes, ds->dps_ierrors));
    l += strlen(l);
    (void)sprintf(l, "O %-12s",
		  cnts_str(ds->dps_opackets, ds->dps_obytes, ds->dps_oerrors));
    l += strlen(l);

    while (*(l-1) == ' ')
	l--;

    *l++ = '\n';

    cl = expand_dir_file("$DPLOG_DIR", CALL_LOG);
    if ((f = open(cl, O_WRONLY|O_APPEND|O_CREAT, 0666)) < 0) {
	d_log(DLOG_DIAG, WHERE, "Can't open call log, %m");
	(void)free(cl);
	return;
    }
    (void)write(f, lbuf, l-lbuf);
    (void)close(f);
    (void)free(cl);
}

char *
cnts_str(pkts, bytes, errs)
u_int pkts, bytes, errs;
{
    static char cbuf[32];
    if (errs)
	(void)sprintf(cbuf, "%d/%d/%d", pkts, bytes, errs);
    else
	(void)sprintf(cbuf, "%d/%d", pkts, bytes);
    return cbuf;
}

char *
sctime(t)
time_t *t;
{
    static char tbuf[24];
    (void)strftime(tbuf, sizeof(tbuf), "%D %T", localtime(t));
    return tbuf;
}

char *
port_str(dlu, pkt)
dl_unitdata_ind_t *dlu;
char *pkt;
{
    struct ip *ip;
    struct protoent *pe;
    struct servent *se;
    char *proto, *port = (char *)0, prbuf[10], ptbuf[10];
    static char pbuf[50];
    ulong pr;

    pr = DP_DLSAP_PROTO(*(ulong *)(((char *)dlu) + dlu->dl_dest_addr_offset));
    switch (pr & ~DPP_DIAL_REQ) {
     case PPP_IP:
	ip = (struct ip *)pkt;
	if (pe = getprotobynumber((int)ip->ip_p)) {
	    proto = pe->p_name;

	    switch (ip->ip_p) {
	     case IPPROTO_TCP:
		{
		    struct tcphdr *th;
		    int iplen = ip->ip_hl << 2;
		    th = (struct tcphdr *)&((char *)ip)[iplen];
		    if ((se = getservbyport((int)th->th_dport, proto)) ||
			(se = getservbyport((int)th->th_sport, proto)))
			port = se->s_name;
		    else {
			(void)sprintf(ptbuf, "%d", th->th_dport);
			port = ptbuf;
		    }
		}
		break;
	     case IPPROTO_UDP:
		{
		    struct udphdr *uh;
		    int iplen = ip->ip_hl << 2;
		    uh = (struct udphdr *)&((char *)ip)[iplen];
		    if ((se = getservbyport((int)uh->uh_dport, proto)) ||
			(se = getservbyport((int)uh->uh_sport, proto)))
			port = se->s_name;
		    else {
			(void)sprintf(ptbuf, "%d", uh->uh_dport);
			port = ptbuf;
		    }
		}
		break;
	    }
	}
	else {
	    (void)sprintf(prbuf, "%d", ip->ip_p);
	    proto = prbuf;
	}

	if (port)
	    (void)sprintf(pbuf, "ip/%s/%s", proto, port);
	else
	    (void)sprintf(pbuf, "ip/%s", proto);
	break;

     default:
	sprintf(pbuf, "Unknown_proto=%04x", pr);
	break;
    }
    return pbuf;
}

/*
 *  Get the packet counts from the interface.
 */

getpacketcounts(rp, ds)
REMOTE *rp;
dp_stats_t *ds;
{
    static char	WHERE[] = "getpacketcounts";
    int s;

    if (strioctl(rp->DlpiFd, DPIOCGIFSTATS, -1, sizeof(*ds), (char *)ds) < 0) {
	d_log(DLOG_GENERAL, WHERE, "Can't DPIOCGIFSTATS for \"%s\", %m",
	      rp->Device);
	unlock_pid();
	exit(1);
    }
}
