/* $Header: /mit/nit/src/nw11/RCS/packet.c,v 1.8 89/10/24 19:08:06 mar Exp $ */


#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/if_ether.h>
#include <net/nit.h>
#include <net/nip.h>

#include "netwatch.h"


struct hashtab *ht;

getpacket(s)
int	s;
{
    register struct nit_hdr *nh;
    unsigned char buf[CHUNKSIZE], buf2[CHUNKSIZE];
    register int i, j;

    i = read(s, buf, sizeof(buf));
    if (i < 0)
      NWError("read");
    j = 0;
    while (i > j) {
#ifdef ibm032
	/* if not longword aligned, copy it so it is */
	if (j & 0x3) {
	    bcopy(&buf[j], buf2, sizeof(struct nit_hdr));
	    nh = (struct nit_hdr *) buf2;
	    if (nh->nh_state == NIT_CATCH && nh->nh_datalen > 0)
		bcopy(&buf[j + sizeof(struct nit_hdr)],
		      &buf2[sizeof(struct nit_hdr)],
		      nh->nh_datalen);
	} else
#endif ibm032
	  nh = (struct nit_hdr *) &buf[j];
	dopacket((unsigned char *) nh);
	j += sizeof(struct nit_hdr) +
	     ((nh->nh_state == NIT_CATCH) ? nh->nh_datalen : 0);
    }
}


dopacket(p)
register unsigned char	*p;
{
    register struct nit_hdr *nh;
    register struct ether_header *eh;
    unsigned char tmp[256];
    char pbuf[1024];

    nh = (struct nit_hdr *) p;
    p += sizeof(struct nit_hdr);
    eh = (struct ether_header *) p;
    p += sizeof(struct ether_header);

    if (nh->nh_state != NIT_CATCH) {
	if (!(mode & LOSSAGE))
	  return;
	sprintf(pbuf, "** %D PACKETS LOST **", nh->nh_dropped);
	display_line(&pbuf[0]);
	if (mode & LOGPACKETS)
	  fwrite(nh, 1, sizeof(struct nit_hdr), logp);
	if (mode & LOGASCII)
	  fprintf(loga, "%s\n", pbuf);
	return;
    }

    /* filter protocols and addresses */
    if (!checkmatch(&protmatch, (u_char *)eh) ||
	!checkmatch(&addrmatch, (u_char *)eh))
      return;

    /* binary log file */
    if (mode & LOGPACKETS)
      fwrite(nh, 1, sizeof(struct nit_hdr) + nh->nh_datalen, logp);

    /* now do display */
    pbuf[0] = 0;

    if (mode & TIMESTAMPS) {
	struct tm *t = localtime(&nh->nh_timestamp.tv_sec);
	sprintf(tmp, "%02d:%02d:%02d.%02d ", t->tm_hour, t->tm_min, t->tm_sec,
		(nh->nh_timestamp.tv_usec/10000)%100);
	strcat(pbuf, tmp);
    }

    if (mode & MANUFACTURERS) {
	int man = (eh->ether_shost[0] << 16) | (eh->ether_shost[1] << 8) |
	  	  eh->ether_shost[2];
	switch (man) {
	case 0x08002b:
	case 0xaa0004:
	case 0xaa0003:
	    strcat(pbuf, "DEC    ");
	    break;
	case 0x020701:
	    strcat(pbuf, "INTRLN ");
	    break;
	case 0x080005:
	    strcat(pbuf, "SYMBLC ");
	    break;
	case 0x02608c:
	    strcat(pbuf, "3COM   ");
	    break;
	case 0x080020:
	    strcat(pbuf, "SUN    ");
	    break;
	case 0x00dd00:
	case 0x00dd01:
	    strcat(pbuf, "UNG/BS ");
	    break;
	default:
	    strcat(pbuf, "???    ");
	}
    }

    if ((mode & PHYSICAL) || (~mode & SYMBOLIC)) {
	sprintf(tmp, "%02x%02x%02x%02x%02x%02x -> ",
		eh->ether_shost[0], eh->ether_shost[1], eh->ether_shost[2],
		eh->ether_shost[3], eh->ether_shost[4], eh->ether_shost[5]);
	strcat(pbuf, tmp);
	if ((eh->ether_dhost[0] == 0xff) && (eh->ether_dhost[1] == 0xff) &&
	    (eh->ether_dhost[2] == 0xff) && (eh->ether_dhost[3] == 0xff) &&
	    (eh->ether_dhost[4] == 0xff) && (eh->ether_dhost[5] == 0xff))
	  strcat(pbuf, "broadcast    ");
	else {
	    sprintf(tmp, "%02x%02x%02x%02x%02x%02x ",
		    eh->ether_dhost[0], eh->ether_dhost[1], eh->ether_dhost[2],
		    eh->ether_dhost[3], eh->ether_dhost[4], eh->ether_dhost[5]);
	    strcat(pbuf, tmp);
	}
    }

    if (mode & LENGTH) {
	sprintf(tmp, "(%4d) ", nh->nh_wirelen);
	strcat(pbuf, tmp);
    }

    if (~mode & SYMBOLIC) {
	sprintf(tmp, "%04x ", ntohs(eh->ether_type));
	strcat(pbuf, tmp);
    } else {
	switch (ntohs(eh->ether_type)) {
	case ETHERTYPE_IP:
	    do_ip(&pbuf[0], p);
	    break;
	case ETHERTYPE_CHAOS:
	    do_chaos(&pbuf[0], p);
	    break;
	case ETHERTYPE_ARP:
	    do_arp(&pbuf[0], p);
	    break;
	case ETHERTYPE_PUP:
	    strcat(&pbuf[0], "PUP ");
	    break;
#ifdef ETHERTYPE_REVARP
	case ETHERTYPE_REVARP:
	    strcat(&pbuf[0], "REVARP ");
	    break;
#endif
	case ETHERTYPE_TRAIL:
	case ETHERTYPE_TRAIL + 1:
	case ETHERTYPE_TRAIL + 2:
	case ETHERTYPE_TRAIL + 3:
	    strcat(&pbuf[0], "IP/trailer ");
	    break;
	case ETHERTYPE_NIP:
	    do_nip(&pbuf[0], p);
	    break;
	case 0x6003:
	    do_dna(&pbuf[0], p);
	    break;
	case 0x6002:
	    strcat(&pbuf[0], "MOP ");
	    break;
	case 0x004c:
	case 0x0024:
	default:
	    sprintf(tmp, "%04x ", ntohs(eh->ether_type));
	    strcat(pbuf, tmp);
	} 
    }

    if (mode & DATA) {
	sprintf(tmp, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
		p[offset + 0], p[offset + 1], p[offset + 2], p[offset + 3],
		p[offset + 4], p[offset + 5], p[offset + 6], p[offset + 7],
		p[offset + 8], p[offset + 9], p[offset + 10], p[offset + 11]);
	strcat(pbuf, tmp);
    }

    /* log file */
    if (mode & LOGASCII)
      fprintf(loga, "%s\n", pbuf);

    display_line(pbuf);
}
