#include <stdlib.h>
#include <stdio.h>

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

#ifdef __FreeBSD__
#include <sys/resource.h>
#endif

#ifndef SOLARIS
#include <strings.h>
#endif
#include <string.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>

#include <pcap-int.h>
#include <pcap.h>

pcap_t *pd = NULL;
static u_long localnet, netmask;

#define SNAPSIZE 54
 
unsigned long last_t_sec = 0, n_packets = 0;

struct fddi_header {
   unsigned char fc;         /* Frame control */
   unsigned char dest[6];    /* MAC addresses */
   unsigned char source[6];
   };

struct ether_header {
   unsigned char dest[6];    /* MAC addresses */
   unsigned char source[6];
   unsigned char type[2];    /* Length or protocol type */
   };

struct llc {
   unsigned char lsap[2];
   unsigned char ui;
   unsigned char orgcode[3];
   unsigned char ethertype[2];
   };

#define NET_SHORT(a)  (a[0] << 8 | a[1])

void ether_callback(u_char *user, struct pcap_pkthdr *h, u_char *p)
{
   struct ether_header *ethp;
   struct llc *llcp;
   unsigned int ethertype, lsap;
   int len, j;

   ethp = (struct ether_header *)p;
   ethertype = NET_SHORT(ethp->type);
   p += sizeof(struct ether_header);
   if (ethertype <= 1500) {  /* 802.3 packet */
      llcp = (struct llc *)p;
      lsap = NET_SHORT(llcp->lsap);
      ethertype = lsap == 0xAAAA ?  /* SNAP packet */
         NET_SHORT(llcp->ethertype) : 0;
      p += sizeof(struct llc);
      printf("%5u  lsap=%04X  type=%04X\n", 
         h->len, lsap, ethertype);
      }
   else lsap = 0;  /* Blue book packet */

   if (h->ts.tv_sec != last_t_sec) {
      printf("----- %u packets\n", n_packets);
      last_t_sec = h->ts.tv_sec;
      n_packets = 1;      
      }
   else ++n_packets;

#ifdef XXYYZZ
   printf("%5u  ", h->len);
   for (j = 0; j != 20; ++j) printf("%02x ",p[j]);
   printf("\n");
#endif
   }

void fddi_callback(u_char *user, struct pcap_pkthdr *h, u_char *p)
{
   struct fddi_header *fddihp;
   struct llc *llcp;
   unsigned int lsap;
   int len;

   fddihp = (struct fddi_header *)p;
   if ((fddihp->fc & 0xF0) == 0x50) {  /* Async LLC frame */
      p += sizeof(struct fddi_header);
      llcp = (struct llc *)p;
      lsap = NET_SHORT(llcp->lsap);
      if (lsap == 0xAAAA) {
         len = h->len;
         p += sizeof(struct llc);
         }
      printf("%5u  lsap=%04X\n", 
         h->len, lsap);
      }
   }

pcap_handler callback;

static pcap_t *init(char *device)
{
   pcap_t *pd = NULL;
   char errbuf[PCAP_ERRBUF_SIZE];
   int type;

   if (!device)
      if (!(device = pcap_lookupdev(errbuf))) {
         printf("pcap_lookupdevice(): %s\n",errbuf);
         return NULL;
         }
   if (pd = pcap_open_live(device, SNAPSIZE, 1, 250, errbuf)) {
      if ((pcap_lookupnet (device, &localnet, &netmask, errbuf)) < 0) {
         printf("pcap_lookupnet(%s): %s\n", device,errbuf);
         return NULL;
         }
      } 
   else {
      printf("pcap_open_live(%s): %s\n", device,errbuf);
      return NULL;
      }
   setuid(getuid());

   type = pcap_datalink(pd);
   if (type == DLT_EN10MB)
      callback = (pcap_handler)ether_callback;
   else if (type == DLT_FDDI)
      callback = (pcap_handler)fddi_callback;
   else {   
      printf("pcap bad link type 0x%x!\n", type);
      pcap_close(pd);
      return NULL;
      }
   return pd;
   }

int main(int argc, char *argv[])
{
   static char *device = "ec0";
#ifndef __FreeBSD__
   int pf, width = ulimit(4, NULL);
#else
   int pf, width;
   struct rlimit reslimit;
#endif /* FreeBSD */
     fd_set readmask;
     struct timeval wait;
#ifdef __FreeBSD__
  if (getrlimit(RLIMIT_NOFILE,&reslimit) != 0) return;
  width = reslimit.rlim_cur;
#endif /* FreeBSD */
  
     if ((pd = init(device)) == NULL) return;
   int pf, width = ulimit(4, NULL);
   fd_set readmask;
   struct timeval wait;

   if ((pd = init(device)) == NULL) return;

   wait.tv_sec = 1;  wait.tv_usec = 0;
   pf = pd->fd;
/*   if (lfd >= 0) FD_SET (lfd, &readmask); */
   FD_ZERO(&readmask);
   FD_SET(pf,&readmask);

   while (select(width, &readmask, NULL, NULL, &wait) >= 0) {
      if (FD_ISSET(pf, &readmask))
         pcap_read(pd, -1, callback, (u_char *)NULL);
/*      if ((lfd >= 0) && FD_ISSET (lfd, &readmask))
         check_client_status (lfd); */

/*      if (lfd >= 0) FD_SET(lfd, &readmask); */
      FD_SET(pf, &readmask);
      }

   pcap_close (pd);
   }

