/* Convert from SNOOP file format (cf RFC 1761) */

#include <sys/types.h>
#include <sys/time.h>

#include <netinet/in.h>

#include <pcap.h>
#include <signal.h>
#include <stdio.h>
#ifdef __STDC__
#include <stdlib.h>
#endif
#include <unistd.h>
#include <string.h>

#include "os.h"			/* operating system stuff */
#include "md.h"			/* machine dependent stuff */

struct snoop_file_header {
	char magic[8];
	int32 version;
	int32 datalink;
} sfh;
#define SNOOP_MAGIC	"snoop\0\0\0"
#define SNOOP_VERSION	2
#define SNOOP_802_3	0
#define SNOOP_802_4	1
#define SNOOP_802_5	2
#define SNOOP_802_6	3
#define SNOOP_ETHERNET	4
#define SNOOP_HDLC	5
#define SNOOP_SYNC	6
#define SNOOP_IBM	7
#define SNOOP_FDDI	8
#define SNOOP_OTHER	9

struct pcap_file_header pfh;
#define TCPDUMP_MAGIC 0xa1b2c3d4

struct snoop_pkthdr {
	int32 olength;
	int32 ilength;
	int32 prlength;
	int32 drops;
	int32 seconds;
	int32 useconds;
} sph;

struct pcap_pkthdr pph;

char buf[65536];
int length, drops, packets = 0;

main() {
	if (fread((char *)&sfh, sizeof(sfh), 1, stdin) != 1) {
		perror("fread snoop_file_header:");
		exit(1);
	}
	if (bcmp(sfh.magic, SNOOP_MAGIC, 8) != 0) {
		fprintf(stderr, "bad magic %s\n", sfh.magic);
		exit(1);
	}
	if (ntohl(sfh.version) != SNOOP_VERSION) {
		fprintf(stderr, "bad version %d\n", ntohl(sfh.version));
		exit(1);
	}

	pfh.magic = htonl(TCPDUMP_MAGIC);
	pfh.version_major = htons(PCAP_VERSION_MAJOR);
	pfh.version_minor = htons(PCAP_VERSION_MINOR);
	pfh.thiszone = 0;
	pfh.sigfigs = 0;
	pfh.snaplen = htonl(16384);
	switch (htonl(sfh.datalink)) {
	    case SNOOP_802_3:
	    case SNOOP_802_4:
	    case SNOOP_802_5:
	    case SNOOP_802_6:
		pfh.linktype = htonl(DLT_IEEE802);
		break;
	    case SNOOP_ETHERNET:
		pfh.linktype = htonl(DLT_EN10MB);
		break;
	    case SNOOP_HDLC:
		pfh.linktype = htonl(DLT_PPP);
		break;
	    case SNOOP_FDDI:
		pfh.linktype = htonl(DLT_FDDI);
		break;
	    default:
		pfh.linktype = htonl(DLT_NULL);
		break;
	}
	if (fwrite((char *)&pfh, sizeof(pfh), 1, stdout) != 1) {
		perror("fwrite pcap_file_header:");
		exit(1);
	}

	while (fread((char *)&sph, sizeof(sph), 1, stdin) == 1) {
		length = ntohl(sph.prlength) - sizeof(sph);
		if (length > sizeof(buf)) {
			fprintf(stderr, "buffer overflow %d\n", length);
			exit(1);
		}
		packets++;
		pph.ts.tv_sec = sph.seconds;
		pph.ts.tv_usec = sph.useconds;
		pph.caplen = sph.ilength;
		pph.len = sph.olength;
		drops = ntohl(sph.drops);
		if (fwrite((char *)&pph, sizeof(pph), 1, stdout) != 1) {
			perror("fwrite pcap_pkthdr:");
			exit(1);
		}
		if (fread(buf, length, 1, stdin) != 1) {
			perror("fread packet:");
			break;
		}
		if (fwrite(buf, ntohl(sph.ilength), 1, stdout) != 1) {
			perror("fwrite packet:");
			exit(1);
		}
	}
	fprintf(stderr, "drops = %d, packets = %d\n", drops, packets);
	exit(0);
}
