/*
 * quick and dirty ethernet sniffer for vxworks.
 * Provided as an example.  It did its work for me but there is no
 * guarantee that it will work for you.
 *
 * Written by Hwa-Jin Bae, bae@mail.com, Piedmont California
 */

#include "vxWorks.h"
#include "sys/types.h"
#include "ioLib.h"
#include "iosLib.h"
#include "fioLib.h"
#include "stdio.h"
#include "unistd.h"
#include "string.h"
#include "usrLib.h"
#include "errnoLib.h"
#include "hostLib.h"
#include "sockLib.h"
#include "socket.h"
#include "inetLib.h"
#include "in.h"
#include "selectLib.h"
#include "taskLib.h"
#include "dosFsLib.h"
#include "etherLib.h"
#include "systm.h"
#include "mbuf.h"
#include "domain.h"
#include "tickLib.h"
#include "protosw.h"
#include "socket.h"
#include "errno.h"
#include "if.h"
#include "route.h"
#include "in.h"
#include "in_pcb.h"
#include "in_systm.h"
#include "in_var.h"
#include "ip.h"
#include "ip_var.h"
#include "ip_icmp.h"
#include "udp.h"
#include "tcp.h"
#include "if_ether.h"
#include "systm.h"
#include "inetLib.h"

char vxSniffLog[200][200];
int vxSniffLogIdx= 0;

STATUS
vxSniffHook(struct ifnet *ifp, char *buf, int len)
{
        struct ip *ip;
        struct  udphdr *udp;
        struct tcphdr *tcp;
        unsigned long ticks;
        char *proto;
        int optlen;
        char srcAddr[20], dstAddr[20];
        char protoxxx[10];

        ip = (struct ip *)(buf + 14);
        inet_ntoa_b(ip->ip_src, srcAddr);
        inet_ntoa_b(ip->ip_dst, dstAddr);
        switch (ip->ip_p) {
        case IPPROTO_TCP:
		proto =	"TCP";
		break;
        case IPPROTO_UDP:
		proto =	"UDP";
		break;
        case IPPROTO_ICMP:
		proto =	"ICMP";
		break;
        default:
		sprintf(protoxxx, "?0x%x", ip->ip_p);
		proto =	protoxxx;
		break;
        }

        ticks = tickGet ();
        
        sprintf(vxSniffLog[vxSniffLogIdx++],
		"0x%x:IP(p:%s,v:%d,h:%d,l:%d) %s -> %s\n", 
		ticks,
		proto,
		(ip->ip_v_hl>>4)&0xf, 
		(ip->ip_v_hl & 0xf)<<2,	ip->ip_len,
		srcAddr, dstAddr);

        if (vxSniffLogIdx == 200)
		vxSniffLogIdx =	0;

        optlen = ((ip->ip_v_hl & 0xf)<<2) - sizeof( struct ip );
        if (ip->ip_p == IPPROTO_UDP) {
		udp = (struct udphdr *)((char *)(ip + 1) + optlen);
		sprintf(vxSniffLog[vxSniffLogIdx++],
			"    UDP(s:%d,d:%d,l:%d)\n",
			udp->uh_sport, udp->uh_dport,
			udp->uh_ulen);
        } else if (ip->ip_p == IPPROTO_TCP) {
		tcp = (struct tcphdr *)((char *)(ip + 1) + optlen);
		sprintf(vxSniffLog[vxSniffLogIdx++],
			"    TCP(s:%d,d:%d,q:%d,a:%d,f:0x%x,w:%d)\n",
			tcp->th_sport, tcp->th_dport,
			tcp->th_seq, tcp->th_ack, tcp->th_flags,
			tcp->th_win);
        }

        if (vxSniffLogIdx == 200)
		vxSniffLogIdx =	0;

        return FALSE;
}

int vxSniffStartIdx = 0;

void
vxSniffStart()
{
        vxSniffStartIdx = vxSniffLogIdx;
}

void
vxSniffShow()
{
        int end = vxSniffLogIdx;
        int i;

        if (end < vxSniffStartIdx) {
		for (i = vxSniffStartIdx; i < 200; i++)
			printf("%s", vxSniffLog[i]);
		for (i = 0; i <	end; i++)
			printf("%s", vxSniffLog[i]);
        } else {
		for (i = vxSniffStartIdx; i < end; i++)
			printf("%s", vxSniffLog[i]);
        }
}

void
vxSniffInit()
{
        /* XXX do something here to put ethernet driver in promiscuous mode */

        etherInputHookAdd(vxSniffHook);
}

