#ifndef lint
static  char sccsid[] = "@(#)rpc.etherd.c 1.1 86/02/05 Copyr 1985 Sun Micro";
#endif

static char rcsid[]=
  "$Header: etherif3.c,v 1.2 93/10/11 15:57:14 mogul Exp $";

/* 
 *         etherif3.c:  NIT interface routine for Sun OS 3.x.
 *
 *  This routine is extracted from Sun Microsystems module protected by the
 *  following copyrights:
 *
 */
 
/*
 * Copyright (c) 1985 by Sun Microsystems, Inc.
 */

/* CHANGES:
 *      Rel 3.0:
 *   ISI: This routine created from etherif.c
 */
  
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <net/if.h>
#include <net/nit.h>

#include "stat.h"
    /* Following needed for packet (size)  */
#include "packet.h"

#define DEBUG

#define CHUNKSIZE       3072    /* was 8192 */
#define BUFSPACE        4*CHUNKSIZE
#define ALIGNMENT        4   /* align on integer boundaries */
#define NIT_DEV         "/dev/nit"
#define FBUFSIZE        600000

int  if_fd = -1;
        
u_long  chunksize;
u_long  snaplen = ((sizeof(struct ether_header) 
                    + 64 /* Max IP hdr */
                    + sizeof(union ip_data)
                    + 3) / 4) * 4; /* even 4-byte boundary */
/* sizeof headers (20) + snaplen (108) = 128 */
/* (snaplen + nit headers) should ideally divide chunksize */

u_char  *buf;
int ndebug = 0;

readether()
{
    register u_char *bp, *bufstop, *cp;
    int cc, datalen, len;
    struct nit_hdr *nh;

    bp =  buf;
    len = 0;  /* buffer is empty */

    if (if_fd < 0) return;

    if ((cc = read(if_fd, (u_char *)buf+len, (int)chunksize-len)) < 0 ) {   
            /* attempt to clear the error condition */
        lseek(if_fd, 0, 0);
        if ((cc = read(if_fd, (u_char *)buf+len, (int)chunksize-len)) < 0) {
            perror("Packet buffer read");
            exit(1);
        }
    }
    len += cc;
    if (len == 0) { 
        return; 
    }        

        /*
         *   Loop through the buffer, obeying alignment rule. 
         */
    bufstop = buf + len;                                                     
    for (bp = buf; bp < bufstop;
            bp += ((sizeof(struct nit_hdr)+datalen+ALIGNMENT-1) & 
                                                ~(ALIGNMENT-1))) {
        nh = (struct nit_hdr *) bp;
        cp = bp + sizeof(struct nit_hdr) ;
        datalen = nh->nh_datalen;

        if (nh->nh_state != NIT_CATCH) {
            switch (nh->nh_state) {
            case NIT_SEQNO:
            case NIT_NOMBUF:
            case NIT_NOCLUSTER:
            case NIT_NOSPACE:
                datalen = 0;
                continue;
            default:
                fprintf(stderr, "NNStat: bad nit state %d\n", nh->nh_state);
                continue;
            }
        }
    
                /* Call parser with packet */        
        parse( cp, datalen,  nh->nh_wirelen,  nh->nh_timestamp);                                                    
    }  /* end loop through buffer */
        
    return;
} /* readether */


/*
 *   Create Network Interface Tap (NIT) Protocol socket and initialize it.
 *    Can look for specified Ethernet type, or NT_ALLTYPES.
 *
 */
initdevice(EtherType)
    int EtherType;
    {
    extern char *EtherIface;
    struct sockaddr_nit snit;
    struct nit_ioc nioc;

    chunksize = CHUNKSIZE;

    if ((buf = (u_char *) malloc(chunksize)) == NULL) {
        printf("MEMORY SHORTAGE: packet buf\n");
        exit(1);
    }      
    
        /* Open NIT device */     
    
    if (if_fd < 0) {
        if_fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
        if (if_fd < 0) {
            perror("nit socket");
            exit(-1);
        }

        snit.snit_family = AF_NIT;
        strncpy(snit.snit_ifname, EtherIface, NITIFSIZ);
        if (bind(if_fd, &snit, sizeof(snit)) != 0) {
            perror(EtherIface);
            exit (1);
        }

        bzero(&nioc, sizeof(nioc));
        nioc.nioc_bufspace = BUFSPACE;
        nioc.nioc_chunksize = chunksize;
        nioc.nioc_typetomatch = EtherType;
        nioc.nioc_snaplen = snaplen;
        nioc.nioc_bufalign = ALIGNMENT ;
        nioc.nioc_bufoffset = 0;
        nioc.nioc_flags = NF_PROMISC|NF_TIMEOUT;
        nioc.nioc_timeout.tv_sec = 1;
        nioc.nioc_timeout.tv_usec = 0;

        if (ioctl(if_fd, SIOCSNIT, &nioc) != 0) {
            perror("nit ioctl");
            exit(1);
        }
    }
} /* initdevice */

deinitdevice()
{
    close(if_fd);
    if_fd = -1;
    free(buf);
}

      
/*
 * returns TRUE IFF something interesting to report.
 *    Doesn't reference "outp" if it returns FALSE.
 */
boolean if_stats(outp)
char *outp;
{
      /* XXX Finish this code XXX */
      return(FALSE);
}
