/*
 * 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.
 *
 */
#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 <net/if.h>
#include "ppp.h"
#include "dp.h"
#include "dpio.h"
#include "dpd.h"

typedef struct pkt {
    time_t time;
    ulong ppa;
    dl_unitdata_ind_t *dlu;
    char *pkt;
} pkt_t;

int pkt_buf[1024+PPP_MTU/sizeof(int)];

char *argv0;
main(argc, argv)
int argc;
char **argv;
{
    pkt_t pkt;
    char *tf;
    FILE *rf;

    argv0 = argv[0];

    init_pathconf();
    tf = expand_dir_file("$DPLOG_DIR", TRACE_FILE);
    rf = fopen(tf, "r");

    if (rf == NULL) {
	fprintf(stderr, "%s: can't open trace file \"%s\"\n", argv0, tf);
	exit(1);
    }
    while (get_req(rf, &pkt))
	print_req(&pkt);
}

get_req(rf, pkt)
FILE *rf;
pkt_t *pkt;
{
    int n;
    pkt_trace_t pt;
    if (!fread((char *)&pt, sizeof(pt), 1, rf))
	return 0;
    if (pt.dlu_len + pt.pkt_len > sizeof(pkt_buf)) {
	fprintf(stderr, "%s: corrupted trace file\n", argv0);
	return 0;
    }
    pkt->time = pt.time;
    pkt->ppa  = pt.ppa;
    pkt->dlu  = (dl_unitdata_ind_t *)pkt_buf;
    pkt->pkt  = ((char *)pkt_buf) + pt.dlu_len;
    if (!fread((char *)pkt->dlu, pt.dlu_len, 1, rf))
	return 0;
    return fread((char *)pkt->pkt, pt.pkt_len, 1, rf);
}

void
dlsap2ph(ph, sap)
phdr_t *ph;
ulong sap;
{
    ph->ph_address  = DP_DLSAP_ADDR(sap);
    ph->ph_control  = DP_DLSAP_CTL(sap);
    ph->ph_protocol = DP_DLSAP_PROTO(sap);
}

print_req(pkt)
pkt_t *pkt;
{
    ulong dlsap;
    phdr_t phdr;
    phdr_t *ph;
    printf("dp%-2d ", pkt->ppa);
    printf("%s", ctime(&pkt->time));
    dlsap = *(ulong *)(((char *)pkt->dlu) + pkt->dlu->dl_dest_addr_offset);
    switch (DP_DLSAP_PROTO(dlsap) & ~DPP_DIAL_REQ) {

     default:
	/*
	 * We should not get an unsupported protocol....
	 */
	dlsap2ph(&phdr, dlsap);
	printf("Unknown protocol %02x:%02x:%04x\n",
	      phdr.ph_address,
	      phdr.ph_control,
	      ntohs(phdr.ph_protocol));

     case PPP_IP:
	print_ip((struct ip *)pkt->pkt);
	break;
    }
    printf("\n");
}

print_ip(ip)
struct ip *ip;
{
    struct udphdr *uh;
    char line1[64], line2[64];
    sprintf(line1, "ip: len:     %3d", ip->ip_len);
    switch (ip->ip_p) {
     case IPPROTO_TCP:
	sprintf(line2, "    proto:   TCP");
	break;
     case IPPROTO_UDP:
	sprintf(line2, "    proto:   UDP");
	break;
     case IPPROTO_ICMP:
	sprintf(line2, "    proto:  ICMP");
	break;
     default:
	sprintf(line2, "    proto:   %3d", ip->ip_p);
	break;
    }
    switch (ip->ip_p) {
     case IPPROTO_TCP:
	{
	    struct tcphdr *th = (struct tcphdr *)(ip+1);
	    printf("%-16s src:  %s.%d\n", line1,
		   inet_ntoa(ip->ip_src), th->th_sport);
	    printf("%-16s dst:  %s.%d\n", line2,
		   inet_ntoa(ip->ip_dst), th->th_dport);
	}
	break;
     case IPPROTO_UDP:
	{
	    struct udphdr *uh = (struct udphdr *)(ip+1);
	    printf("%-16s src:  %s.%d\n", line1,
		   inet_ntoa(ip->ip_src), uh->uh_sport);
	    printf("%-16s dst:  %s.%d\n", line2,
		   inet_ntoa(ip->ip_dst), uh->uh_dport);
	}
	break;
     default:
	printf("%-16s src:  %s\n", line1, inet_ntoa(ip->ip_src));
	printf("%-16s dst:  %s\n", line2, inet_ntoa(ip->ip_dst));
	break;
    }
}

print_sin(sin)
struct sockaddr_in *sin;
{
    printf("dst: family: %2d  ", sin->sin_family);
    printf("addr: %s\n", inet_ntoa(sin->sin_addr));
}

#include <varargs.h>

void
yyerror(va_alist)
va_dcl
{
    va_list ap;
    char *path,
	 *fmt,
	 buff[256];
    extern int linenum;

    va_start(ap);
    path = va_arg(ap, char *);
    fmt = va_arg(ap, char *);
    (void)sprintf(buff, "Error near line %d of\n\t\"%s\":  %s",
	linenum, path, fmt);
    fprintf(stderr, "%s: %s\n", argv0, buff);
    va_end(ap);
}
