/* 
Received: from SOUTH-STATION-ANNEX.MIT.EDU by po10.MIT.EDU (5.61/4.7) id AA04075; Sun, 19 Mar 00 00:31:19 EST
Received: from noc.untraceable.net by MIT.EDU with SMTP
	id AA12326; Sun, 19 Mar 00 00:31:05 EST
Received: (from andrew@localhost)
	by noc.untraceable.net (8.10.0/8.10.0/bonk!) id e2J5V7v02327
	for jhawk@MIT.EDU; Sun, 19 Mar 2000 00:31:07 -0500 (EST)
Date: Sun, 19 Mar 2000 00:31:06 -0500
From: Andrew Brown <atatat@atatdot.net>
To: John Hawkinson <jhawk@MIT.EDU>
Subject: Re: pcap/snoop convertor?
Message-Id: <20000319003106.A2287@noc.untraceable.net>
Reply-To: Andrew Brown <atatat@atatdot.net>
References: <200003190507.AAA17526@contents-vnder-pressvre.mit.edu>
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="EVF5PPMfhYS0aIcm"
X-Mailer: Mutt 1.0.1i
In-Reply-To: <200003190507.AAA17526@contents-vnder-pressvre.mit.edu>; from jhawk@MIT.EDU on Sun, Mar 19, 2000 at 12:07:29AM -0500
X-Hi-To-All-My-Friends-In-Domestic-Surveillance: hi there, sports fans  :)
Return-Receipt-To: receipts@daemon.org


--EVF5PPMfhYS0aIcm
Content-Type: text/plain; charset=us-ascii

>I'm sort of looking for a tcpdump/snoop convertor
>in a hurry...is yours available by any chance?
>[ Looks like I may have to write one if I can't find
>one in the next few minutes...]

yep.  attached.  should compile under *bsd or solaris.  translates to
the alternate dump format with local endianness by default.  no man
page, but the defaults should satisfy.

btw - it seems we have a few friends in common (tls, alexis, battlej)
so perhaps next time you're around new york we could do beers?

-- 
|-----< "CODE WARRIOR" >-----|
codewarrior@daemon.org             * "ah!  i see you have the internet
twofsonet@graffiti.com (Andrew Brown)                that goes *ping*!"
andrew@crossbar.com       * "information is power -- share the wealth."

--EVF5PPMfhYS0aIcm
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="pdx.c"
*/

static const char copyright[] = "@(#) (c) 1999-2000 andrew brown :)";
static const char version[] = "@(#) $Id: pdx.c,v 1.3 1999/11/27 01:05:54 andrew Exp andrew $";
char vernum[sizeof("###.###.###.###.###.###\0")]; /* should be plenty */

/*
  
  packet dump exchanger, (c) copyright 1999, andrew brown :)

  currently:
  * reads tcpdump, snoop (would read sniffit, but that'd be difficult)
  * writes tcpdump, snoop (would write sniffit, but that'd be silly)
  * defaults to output of the form opposite to the input
  * snoop output defaults to big-endian
  * tcpdump output defaults to local-endianness

  options:
  * c: - count of packets to read (and write)
  * B  - big endian output
  * h  - help
  * l  - little endian output
  * i: - input file (default stdin)
  * I  - identify input files only
  * o: - output file (default stdout)
  * O: - output type
  * q  - quiet mode (nothing printed to stderr)
  * v  - verbose mode (period printed for each packet)
  
  other arguments:
  * non-option arguments are read as input files
  
 */

#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>

#ifdef __svr4__ /* solaris bites! */
typedef unsigned short u_int16_t;
typedef unsigned int u_int32_t;
#endif

#define WRAPAT 66

#define FILE_UNDEF   0
#define FILE_TCPDUMP 1
#define FILE_SNOOP   2

#define TCPDUMP_MAGIC 0xa1b2c3d4

#define NEEDINSWAP()  (my_end != in_end)
#define NEEDOUTSWAP() (my_end != out_end)

#define ROUNDUP(n,b) (((n-1)|(b-1))+1)

#define ENDIAN_LITTLE 0
#define ENDIAN_BIG    1

struct snoop_fhdr {
  char      sfh_snoop[8];
  u_int32_t sfh_snoopver;
  u_int32_t sfh_snaptype;
};

struct snoop_hdr {
  u_int32_t sh_packlen;
  u_int32_t sh_snaplen;
  u_int32_t sh_reclen;
  u_int32_t sh_drops;
  u_int32_t sh_sec;
  u_int32_t sh_usec;
};

struct tcpdump_fhdr {
  u_int32_t tfh_magic;
  u_int16_t tfh_pcap_major;
  u_int16_t tfh_pcap_minor;
  u_int32_t tfh_timezone;
  u_int32_t tfh_timeacc;
  u_int32_t tfh_caplen;
  u_int32_t tfh_snaptype;
};

struct tcpdump_hdr {
  u_int32_t th_sec;
  u_int32_t th_usec;
  u_int32_t th_snaplen;
  u_int32_t th_packlen;
};

struct packet_header {
  u_int32_t ph_packlen;		/* tcpdump-p, snoop-p */
  u_int32_t ph_snaplen;		/* tcpdump-p, snoop-p */
  u_int32_t ph_reclen;		/* snoop-p */
  u_int32_t ph_timezone;	/* tcpdump-h */
  u_int32_t ph_timeacc;		/* tcpdump-h */
  u_int32_t ph_snaptype;	/* tcpdump-h, snoop-h */
  u_int32_t ph_caplen;		/* tcpdump-h */
  u_int32_t ph_drops;		/* snoop-p */
  u_int32_t ph_sec;		/* tcpdump-p, snoop-p */
  u_int32_t ph_usec;		/* tcpdump-p, snoop-p */
  /* add more fields here if needed for other capture formats */
};

struct output_type {
  char *ot_name;
  int ot_format;
  int ot_endian;
} otypes[] = {
  /* use your imagination here...  :) */
  { "tcpdump",    FILE_TCPDUMP, -1 }, /* -1 means local endian-ness */
  { "snoop",      FILE_SNOOP,   -1 },
  { "tcpdump/be", FILE_TCPDUMP, ENDIAN_BIG },
  { "tcpdump/le", FILE_TCPDUMP, ENDIAN_LITTLE },
  { "tcpdump-be", FILE_TCPDUMP, ENDIAN_BIG },
  { "tcpdump-le", FILE_TCPDUMP, ENDIAN_LITTLE },
  { "snoop/be",   FILE_SNOOP,   ENDIAN_BIG },
  { "snoop/le",   FILE_SNOOP,   ENDIAN_LITTLE },
  { "snoop-be",   FILE_SNOOP,   ENDIAN_BIG },
  { "snoop-le",   FILE_SNOOP,   ENDIAN_LITTLE },
  { "be/tcpdump", FILE_TCPDUMP, ENDIAN_BIG },
  { "le/tcpdump", FILE_TCPDUMP, ENDIAN_LITTLE },
  { "be-tcpdump", FILE_TCPDUMP, ENDIAN_BIG },
  { "le-tcpdump", FILE_TCPDUMP, ENDIAN_LITTLE },
  { "be/snoop",   FILE_SNOOP,   ENDIAN_BIG },
  { "le/snoop",   FILE_SNOOP,   ENDIAN_LITTLE },
  { "be-snoop",   FILE_SNOOP,   ENDIAN_BIG },
  { "le-snoop",   FILE_SNOOP,   ENDIAN_LITTLE },
  { NULL,         FILE_UNDEF,   -1 }};

char *snooptype[]={
  "ieee 802.3",
  "ieee 802.4 token bus",
  "ieee 802.5 token ring",
  "ieee 802.6 metro net",
  "ethernet",
  "hdlc",
  "character synchronous",
  "ibm channel-to-channel",
  "fddi",
  "other",
  NULL};
int snoop2ph[]=
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9};
int ph2snoop[]=
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9};

char *tcptype[]={
  "null",
  "ethernet",
  "en3mb",
  "ax25",
  "pronet",
  "chaos",
  "ieee802",
  "arcnet",
  "slip",
  "ppp",
  "fddi",
  "atm_rfc1483",
  "raw ip",
  "bsd/os slip",
  "bsd/os ppp",
  NULL};
int tcp2ph[]=
{10, 4,11,12,13,14, 0,15,16,17, 8,18,19,20,21, 9, 9, 9, 9, 9, 9, 9};
int ph2tcp[]=
{ 6, 6, 6, 6, 1, 0, 0, 0,10, 0, 0, 2, 3, 4, 5, 7, 8, 9,11,12,13,14};

int my_end, in_end, out_end;
int in_fmt, out_fmt;
int got_oend, got_ofmt;
int rc, verbosity, idonly;
char pbuf[16384], *ifile;
FILE *msgs;

/* these routines need to unilaterally swap bytes, on bigendian or
   little-endian architectures... */
#undef ntohs
#undef htons
#define ntohs(x) swaps(x)
#define htons(x) swaps(x)
static inline u_int16_t
swaps(u_int16_t x)
{
  unsigned char *u=(unsigned char *)&x;
  u[0]^=u[1]^=u[0]^=u[1];
  return x;
}
#undef HTONS
#undef NTOHS
#define HTONS(x) (x=swaps(x))
#define NTOHS(x) (x=swaps(x))
#define SWAPS(x) (x=swaps(x))

#undef ntohl
#undef htonl
#define ntohl(x) swapl(x)
#define htonl(x) swapl(x)
static inline u_int32_t
swapl(u_int32_t x)
{
  unsigned char *u=(unsigned char *)&x;
  u[0]^=u[3]^=u[0]^=u[3];
  u[1]^=u[2]^=u[1]^=u[2];
  return x;
}
#undef HTONL
#undef NTOHL
#define NTOHL(x) (x=swapl(x))
#define HTONL(x) (x=swapl(x))
#define SWAPL(x) (x=swapl(x))

int
out_format(char *str)
{
  struct output_type *otype;
  for (otype = otypes;
       otype->ot_format != FILE_UNDEF;
       otype++) {
    if (strcasecmp(otype->ot_name, str) == 0) {
      if (otype->ot_endian != -1) {
	out_end = otype->ot_endian;
	got_oend = 1;
      }
      return otype->ot_format;
    }
  }

  fprintf(stderr, "** output format name not known: %s\n", str);
  exit(1);
}

void
pickmyendian(void)
{
  int i = 1;
  char *p = (char*)&i;
  if (*p)
    my_end = ENDIAN_LITTLE;
  else
    my_end = ENDIAN_BIG;
}

int
decide_input(int ifd, struct packet_header *ph)
{
  struct snoop_fhdr *sfh = (struct snoop_fhdr *) &pbuf;
  struct tcpdump_fhdr *tfh = (struct tcpdump_fhdr *) &pbuf;
  switch (rc = read(ifd, pbuf, 16))
    {
    case 0:
      /* fprintf(stderr, "** input file empty?\n"); */
      return 0;
    case 16:
      break;
    default:
      if (ifile)
	fprintf(stderr, "** input too short for positive id on %s\n", ifile);
      else if (idonly || verbosity)
	fprintf(stderr, "** standard input too short for positive id\n");
      return 0;
    }
  if (bcmp(sfh->sfh_snoop,"snoop\0\0\0",8)==0) {
    in_fmt = FILE_SNOOP;
    fprintf(msgs, "[input file");
    if (ifile)
      fprintf(msgs, " (%s)", ifile);
    fprintf(msgs, ": snoop");
    in_end = (sfh->sfh_snaptype > 255) ? !my_end : my_end;
    if (NEEDINSWAP()) {
      SWAPL(sfh->sfh_snoopver);
      SWAPL(sfh->sfh_snaptype);
    }
    ph->ph_timezone = 0;	/* snoop doesn't have this... */
    ph->ph_timeacc = 0;		/* ...or this... */
    ph->ph_caplen = 16384;	/* ...or this, so what else can i do? */
    ph->ph_snaptype = snoop2ph[sfh->sfh_snaptype];
    fprintf(msgs,", version %d, %s endian",sfh->sfh_snoopver,
	    in_end == ENDIAN_LITTLE ? "little" : "big");
    fprintf(msgs,", snaptype=%s", snooptype[sfh->sfh_snaptype]);
  }
  else if (tfh->tfh_magic == TCPDUMP_MAGIC ||
	   tfh->tfh_magic == swapl(TCPDUMP_MAGIC)) {
    in_fmt = FILE_TCPDUMP;
    fprintf(msgs, "[input file");
    if (ifile)
      fprintf(msgs, " (%s)", ifile);
    fprintf(msgs, ": tcpdump");
    rc = read(ifd, pbuf + 16, 8); /* get the rest */
    if (tfh->tfh_magic == TCPDUMP_MAGIC)
      in_end = my_end;
    else {
      in_end = !my_end;
      SWAPS(tfh->tfh_pcap_major);
      SWAPS(tfh->tfh_pcap_minor);
      SWAPL(tfh->tfh_timezone);
      SWAPL(tfh->tfh_timeacc);
      SWAPL(tfh->tfh_caplen);
      SWAPL(tfh->tfh_snaptype);
    }
    ph->ph_timezone = tfh->tfh_timezone;
    ph->ph_timeacc = tfh->tfh_timeacc;
    ph->ph_caplen = tfh->tfh_caplen;
    ph->ph_snaptype = tcp2ph[tfh->tfh_snaptype];
    fprintf(msgs,", pcap version %hd.%hd", tfh->tfh_pcap_major,
	    tfh->tfh_pcap_minor);
    fprintf(msgs,", %s endian", in_end == ENDIAN_LITTLE ? "little" : "big");
    fprintf(msgs,", caplen=%d", tfh->tfh_caplen);
    fprintf(msgs,", snaptype=%s", tcptype[tfh->tfh_snaptype]);
  }
  /* add more file input types here */
  else {
    if (ifile)
      fprintf(stderr, "** unknown input file format in %s\n", ifile);
    else /* if (idonly || verbosity) */
      fprintf(stderr, "** unknown input file format on stdin\n");
    return 0;
  }
  fprintf(msgs,"]\n");
  return !idonly;
}

void
start_output(int ofd, struct packet_header *ph)
{
  struct snoop_fhdr *sfh = (struct snoop_fhdr *) &pbuf;
  struct tcpdump_fhdr *tfh = (struct tcpdump_fhdr *) &pbuf;

  switch (out_fmt) {
  case FILE_TCPDUMP:
    tfh->tfh_magic = TCPDUMP_MAGIC;
    tfh->tfh_pcap_major = 2;
    tfh->tfh_pcap_minor = 4;
    tfh->tfh_timezone = ph->ph_timezone;
    tfh->tfh_timeacc = ph->ph_timeacc;
    tfh->tfh_caplen = ph->ph_caplen;
    tfh->tfh_snaptype = ph2tcp[ph->ph_snaptype];
    if (my_end != out_end) {
      SWAPL(tfh->tfh_magic);
      SWAPS(tfh->tfh_pcap_major);
      SWAPS(tfh->tfh_pcap_minor);
      SWAPL(tfh->tfh_timezone);
      SWAPL(tfh->tfh_timeacc);
      SWAPL(tfh->tfh_caplen);
      SWAPL(tfh->tfh_snaptype);
    }
    write(ofd, tfh, sizeof(*tfh));
    break;
  case FILE_SNOOP:
    bcopy("snoop\0\0\0",sfh->sfh_snoop,8);
    sfh->sfh_snoopver = 2;
    sfh->sfh_snaptype = ph2snoop[ph->ph_snaptype];
    if (my_end != out_end) {
      SWAPL(sfh->sfh_snoopver);
      SWAPL(sfh->sfh_snaptype);
    }
    write(ofd, sfh, sizeof(*sfh));
    break;
  }
}

void
decide_output(void)
{
  if (!got_ofmt) {
    switch (in_fmt) {
    case FILE_TCPDUMP:
      out_fmt = FILE_SNOOP;
      break;
    case FILE_SNOOP:
      out_fmt = FILE_TCPDUMP;
      break;
    }
    got_ofmt = 1;
  }
  if (!got_oend) {
    if (out_fmt == FILE_SNOOP)
      out_end = ENDIAN_BIG; /* snoop only writes big endian files */
    else
      out_end = my_end;
    got_oend = 1;
  }
  switch (out_fmt) {
  case FILE_TCPDUMP:
    fprintf(msgs,"[output format: tcpdump");
    break;
  case FILE_SNOOP:
    fprintf(msgs,"[output format: snoop");
    break;
  }
  fprintf(msgs,", %s endian", out_end == ENDIAN_LITTLE ? "little" : "big");
  fprintf(msgs,"]\n");
}

int
get_packet(int ifd, struct packet_header *header, char **data)
{
  int mustread, mustwrite = -1;
  switch (in_fmt) {
  case FILE_TCPDUMP:
    {
      struct tcpdump_hdr *th = (struct tcpdump_hdr*) &pbuf;
      if ((rc = read(ifd, pbuf, sizeof(*th))) != sizeof(*th))
	return -1;
      if (NEEDINSWAP()) {
	SWAPL(th->th_sec);
	SWAPL(th->th_usec);
	SWAPL(th->th_snaplen);
	SWAPL(th->th_packlen);
      }

      header->ph_snaplen = th->th_snaplen;
      header->ph_packlen = th->th_packlen;
      header->ph_reclen = header->ph_snaplen;
      header->ph_snaptype = header->ph_snaptype;
      header->ph_drops = 0; /* tcp doesn't have this */
      header->ph_sec = th->th_sec;
      header->ph_usec = th->th_usec;
      mustread = th->th_snaplen;

#ifdef DEBUG
      fprintf(msgs, "tcpin (s %d, u %d, g %d, p %d)\n",
	      header->ph_sec, header->ph_usec,
	      header->ph_snaplen, header->ph_packlen);
      fprintf(msgs, "tcpin (pl %d, sl %d, rl %d, tz %d, ta %d,\n"
	      "\tst %d, cl %d dp %d, ss %d, su %d)\n",
	      header->ph_packlen, header->ph_snaplen, header->ph_reclen,
	      header->ph_timezone, header->ph_timeacc, header->ph_snaptype,
	      header->ph_caplen, header->ph_drops, header->ph_sec,
	      header->ph_usec);
      fprintf(msgs, "tcpin (s %d, u %d, g %d, p %d)\n",
	      th->th_sec, th->th_usec, th->th_snaplen, th->th_packlen);
      fprintf(msgs, "reading (from tcpdump) %d...\n", mustread);
#endif

      if ((rc = read(ifd, *data = pbuf + sizeof(*th), th->th_snaplen)) !=
	  th->th_snaplen)
	return -1;
      mustwrite = th->th_snaplen;
#ifdef DEBUG
      fprintf(msgs, "mustwrite (from tcpdump) %d...\n", mustwrite);
#endif
      break;
    }
  case FILE_SNOOP:
    {
      struct snoop_hdr *sh = (struct snoop_hdr*) &pbuf;
      if ((rc = read(ifd, pbuf, sizeof(*sh))) != sizeof(*sh))
	return -1;
      if (NEEDINSWAP()) {
	SWAPL(sh->sh_packlen);
	SWAPL(sh->sh_snaplen);
	SWAPL(sh->sh_reclen);
	SWAPL(sh->sh_drops);
	SWAPL(sh->sh_sec);
	SWAPL(sh->sh_usec);
      }

      header->ph_snaplen = sh->sh_snaplen;
      header->ph_packlen = sh->sh_packlen;
      header->ph_reclen = sh->sh_reclen - sizeof(struct snoop_hdr);
      header->ph_snaptype = header->ph_snaptype;
      header->ph_drops = sh->sh_drops;
      header->ph_sec = sh->sh_sec;
      header->ph_usec = sh->sh_usec;
      /* snoop also pads the tail end of the packet apparently */
      mustread = ROUNDUP(sh->sh_snaplen,4);

#ifdef DEBUG
      fprintf(msgs, "snoopin (pl %d, sl %d, rl %d, tz %d, ta %d,\n"
	      "\tst %d, cl %d, dp %d, ss %d, su %d)\n",
	      header->ph_packlen, header->ph_snaplen, header->ph_reclen,
	      header->ph_timezone, header->ph_timeacc, header->ph_snaptype,
	      header->ph_caplen, header->ph_drops, header->ph_sec,
	      header->ph_usec);
      fprintf(msgs, "snoopin (ol %d, sl %d, pl %d, dp %d, ss %d, su %d)\n",
	      sh->sh_packlen, sh->sh_snaplen, sh->sh_reclen,
	      sh->sh_drops, sh->sh_sec, sh->sh_usec);
      fprintf(msgs, "reading (from snoop) %d...\n", mustread);
#endif

      if ((rc = read(ifd, *data = pbuf + sizeof(*sh), mustread)) !=
	  mustread)
	return -1;
      mustwrite = sh->sh_snaplen;
#ifdef DEBUG
      fprintf(msgs, "mustwrite (from snoop) %d...\n", mustwrite);
#endif
      break;
    }
  }
#ifdef DEBUG
  fprintf(msgs, "mustwrite(%d) = %d\n", out_fmt, mustwrite);
#endif
  return mustwrite;
}

void
put_packet(int ofd, struct packet_header *ph, char *data, int dlen)
{
#ifdef DEBUG
  fprintf(msgs, "dlen = %d\n", dlen);
#endif
  switch (out_fmt) {
  case FILE_TCPDUMP:
    {
      struct tcpdump_hdr th;
      th.th_sec = ph->ph_sec;
      th.th_usec = ph->ph_usec;
      th.th_snaplen = ph->ph_snaplen;
      th.th_packlen = ph->ph_packlen;
      if (NEEDOUTSWAP()) {
	SWAPL(th.th_sec);
	SWAPL(th.th_usec);
	SWAPL(th.th_snaplen);
	SWAPL(th.th_packlen);
      }
      write(ofd, &th, sizeof(th));
      break;
    }
  case FILE_SNOOP:
    {
      struct snoop_hdr sh;
      sh.sh_packlen = ph->ph_packlen;
      sh.sh_snaplen = ph->ph_snaplen;
      sh.sh_reclen = ph->ph_reclen + sizeof(struct snoop_hdr);
      sh.sh_drops = ph->ph_drops;
      sh.sh_sec = ph->ph_sec;
      sh.sh_usec = ph->ph_usec;
      if (NEEDOUTSWAP()) {
	SWAPL(sh.sh_packlen);
	SWAPL(sh.sh_snaplen);
	SWAPL(sh.sh_reclen);
	SWAPL(sh.sh_drops);
	SWAPL(sh.sh_sec);
	SWAPL(sh.sh_usec);
      }
      write(ofd, &sh, sizeof(sh));
      dlen = ROUNDUP(dlen, 4);
      break;
    }
  }
  write(ofd,data,dlen);
}

void
usage(void)
{
  const char *t;
  int l;

  t = version;			/* start at version string */
  for(l = 0; l < 3; t++,l++)	/* skip three tokens */
    while (t[0] != ' ') t++;	/* skip to space */
  l = 0;			/* start number here */
  while (t[l] != ' ') l++;	/* find next space */
  strncpy(vernum, t, l);	/* copy out version number */
  vernum[l] = 0;		/* terminate version string */

  printf("%s",
"usage: pdx [-BlIqv] [-c number] [-i input] [-o output] [-O mode] [file...]\n"
"\n"
" c - count of packets to read (and write)\n"
" B - big endian output\n"
" l - little endian output\n"
" h - this help\n"
" i - input file (default stdin)\n"
" I - identify input files only\n"
" o - output file (default stdout)\n"
" O - output type\n"
" q - quiet mode (nothing printed to stderr)\n"
" v - verbose mode (period printed for each packet)\n"
"\n"
" any leftover arguments are used as input files\n"
"\n");

  printf("pdx v%s, %s\n", vernum, copyright);
  
  exit(1);
}

int
main(int argc, char *argv[])
{
  struct packet_header header;
  char *data, *input, *output;
  int dlen, ch, count, dcount, icount, ifd, ofd, output_started;
  
  count = got_oend = got_ofmt = 0;
  ifile = input = output = NULL;
  msgs = stderr;
  verbosity = idonly = output_started = 0;
  
  while ((ch = getopt(argc, argv, "c:Bhli:Io:O:qv")) != EOF)
    switch (ch) {
    case 'c':
      if ((count = atoi(optarg))<0) {
	fprintf(stderr, "** invalid count %s\n", optarg);
	exit(1);
      }
      break;
    case 'B': /* big endian output */
      out_end = ENDIAN_BIG;
      got_oend = 1;
      break;
    case 'l': /* little endian output */
      out_end = ENDIAN_LITTLE;
      got_oend = 1;
      break;
    case 'i': /* input from ... */
      ifile = input = optarg;
      break;
    case 'I': /* identifiles only */
      idonly = 1;
      break;
    case 'o': /* output to ... */
      output = optarg;
      break;
    case 'O': /* output format */
      out_fmt = out_format(optarg);
      got_ofmt = 1;
      break;
    case 'q':
      if (msgs != stderr)
	fclose(msgs);
      if ((msgs = fopen("/dev/null","a")) == NULL) {
	fprintf(stderr, "** open: %s\n", strerror(errno));
	exit(1);
      }
      break;
    case 'v':
      verbosity++;
      break;
    case 'h':
    default:
      usage();
    }
  argc -= optind;
  argv += optind;
  
  if (input) {
    if (argc) {
      fprintf(stderr, "** input file specified and arguments given...\n");
      exit(1);
    }
    if ((ifd = open(input, O_RDONLY)) == -1) {
      fprintf(stderr, "** open(%s): %s\n", input, strerror(errno));
      exit(1);
    }
  }
  else
    ifd = 0;

  if (output) {
    if ((ofd = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
      fprintf(stderr, "** open(%s): %s\n", output, strerror(errno));
      exit(1);
    }
  }
  else
    ofd = 1;

  /* init */
  pickmyendian();

  /* how many packets we've done */
  dcount = 0;
  
  /* we have args, or a valid input source */
  while (argc || ifd > -1) {
    /* we have args...try to process them */
    if (argc) {
      argc--;
      if (ifd > 0)
	close(ifd);
      if ((ifd = open(argv[0], O_RDONLY)) == -1) {
	fprintf(stderr, "** open(%s): %s\n", argv[0], strerror(errno));
	argv++;
	continue;
      }
      ifile = argv[0];
      argv++;
    }
    
    /* figure out what the input type is */
    if (decide_input(ifd, &header)) {
      
      if (!output_started) {
	/* determine output format */
	decide_output();
	
	/* start output */
	start_output(ofd, &header);
	
	output_started = 1;
      }
      
      /* do conversion */
      for (icount = 0;
	   (!count || dcount < count) &&
	     (dlen = get_packet(ifd, &header, &data)) > -1;
	   icount++, dcount++) {
	put_packet(ofd, &header, data, dlen);
	if (verbosity) {
	  fprintf(msgs, ".");
	  if (dcount % WRAPAT == (WRAPAT - 1))
	    fprintf(msgs, "\n");
	  fflush(msgs);
	}
      }
      if (verbosity && dcount % WRAPAT != 0)
	fprintf(msgs, "%d\n", icount);
    }
      
    /* are we processing args? */
    if (ifd > 0)
      close(ifd);
    
    /* either way we're done with this input stream */
    ifd = -1;
    
    /* are we counting output packets? */
    if (count && dcount >= count)
      break;
  }
  
  if (!idonly && dcount)
    fprintf(msgs, "output packet count = %d\n", dcount);
  
  exit(0);
}

/*
--EVF5PPMfhYS0aIcm--
*/
