
 
/****************************************************************************/
/*                                                                          */
/*      NNstat -- Internet Statistics Collection Package                    */
/*                                                                          */
/*            Written by: Bob Braden & Annette DeSchon                      */
/*            USC Information Sciences Institute                            */
/*            Marina del Rey, California                                    */
/*                                                                          */
/*      Copyright (c) 1991 University of Southern California.               */
/*      All rights reserved.                                                */
/*                                                                          */
/*      Redistribution and use in source and binary forms are permitted     */
/*      provided that the above copyright notice and this paragraph are     */
/*      duplicated in all such forms and that any documentation,            */
/*      advertising materials, and other materials related to such          */
/*      distribution and use acknowledge that the software was              */
/*      developed by the University of Southern California, Information     */
/*      Sciences Institute.  The name of the University may not be used     */
/*      to endorse or promote products derived from this software           */
/*      without specific prior written permission.                          */
/*      THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR        */
/*      IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
/*      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR          */
/*      PURPOSE.                                                            */
/*                                                                          */
/****************************************************************************/

static char rcsid[]=
  "$Header: etherdlpi.c,v 1.1 93/09/27 13:11:48 mogul Exp $";

/*
 *     etherdlpi.c -- DLPI interface module for Sun OS 5.x.
 *
 */

/* CHANGES:
 *      Rel 3.0:
 *    ISI:  Move TRACEF code to separate interface routine testif.c
 *    ISI:  Split etherif.c into separate routines for Sun OS 3, Sun OS4:
 *               etherif3.c, etherif4.c [ISI]
 *
 */
  
#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 <sys/dlpi.h>
#include <sys/bufmod.h>

#include <sys/stream.h>
#include <sys/stropts.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 DLPI_DEV       "/dev/le"
#define FBUFSIZE        600000

int  if_fd = -1;

#define TFLAG      /* NI_TIMESTAMP is set */
#define DFLAG      /* NI_DROPS is set */
/* NI_LEN is set since snaplen > 0 */
        
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;   /* Buffer is malloc'd */
int ndebug = 0;
u_long  DLPI_drops = 0;

readether()
{
    struct strbuf strdata;
    struct sb_hdr *hdrp;
    int flags;

    register u_char *bp, *bufstop, *cp;
    int cc, datalen, len;
    struct timeval  *tvp;   /*  = NULL; */
    
    int header_size =  sizeof(*hdrp);

    flags = 0;
    strdata.len = 0;
    strdata.buf = buf;
    strdata.maxlen = chunksize;
    bp =  buf;
            
    if (if_fd < 0) return;
        
    if (getmsg(if_fd, NULL, &strdata, &flags) < 0) {
        perror("Packet buffer read");
        exit(1);
    }

    len += strdata.len;

    if (len == 0)
        return; 

        /*
         *   Loop through the buffer, obeying alignment rule. 
         */
    bufstop = buf + len;                     
    for (bp = buf; bp < bufstop; bp += hdrp->sbh_totlen) {

        cp = bp;
        
        hdrp = (struct sb_hdr *)cp;
        cp += sizeof *hdrp;

	DLPI_drops = hdrp->sbh_drops;

        parse( cp, hdrp->sbh_msglen, hdrp->sbh_origlen, hdrp->sbh_timestamp);

    }  /* end loop through buffer */
        
   return;
} /* readether */


/*
 *   Create a DLPI STREAMS head.
 *
 */
initdevice(EtherType)
    int EtherType;
    {
    extern char *EtherIface;
    struct strioctl si;
    struct ifreq    ifr;
    struct timeval  timeout;
    u_long if_flags = 0;

    chunksize = CHUNKSIZE;
        
    if ((buf = (u_char *) malloc(chunksize)) == NULL) {
        printf("MEMORY SHORTAGE: packet buf\n");
        exit(1);
    }      
    
        /* Open DLPI device */     

    if ((if_fd = open(DLPI_DEV, O_RDONLY)) < 0) {
        perror("DLPI open");
        exit (1);
    }

	/* Attach to the device */
    dlattachreq(if_fd, 0);

    if (dlokack(if_fd, buf) < 0) {
	perror("DLPI attach failed");
	exit(1);
    }

	/* Set promiscous mode in the physical level */
    dlpromisconreq(if_fd, DL_PROMISC_PHYS);

    if (dlokack(if_fd, buf) < 0) {
	perror("DL_PROMISC_PHYS failed");
	exit(1);
    }

	/* bind to the specific unit - I'm a bit disconcerned here since
         * here we say we want only IP packets (Ether-type 0x800) but
         * my tests show that it might be fetching everything after all
         * Will love to be explained about this.
         * -- Amos Shapira (amoss@cs.huji.ac.il)
	 */

    dlbindreq(if_fd, 0x800, 0, DL_CLDLS, 0, 0);

    if (dlbindack(if_fd, buf) < 0) {
	perror("dlbindack failed");
	exit(1);
    }

	/* Set promiscous mode in the SAP level */
    dlpromisconreq(if_fd, DL_PROMISC_SAP);

    if (dlokack(if_fd, buf) < 0) {
	perror("DL_PROMISC_SAP failed");
	exit(1);
    }

	/* Ask for the frame header too */
    si.ic_cmd = DLIOCRAW;
    si.ic_timout = INFTIM;
    si.ic_len = 0;
    si.ic_dp = 0;

    if (ioctl(if_fd, I_STR, &si) < 0) {
	perror("ioctl (I_STR DLIOCRAW)");
	exit(1);
    }

        /*
         * Arrange to get discrete messages from the stream.
         *      RMSGD is Message-discard mode.
         */
    if (ioctl(if_fd, I_SRDOPT, (char *)RMSGD) < 0) {
        perror("ioctl (I_SRDOPT)");
        exit (1);
    }

	/* Buffering module */
    if (ioctl(if_fd, I_PUSH, "bufmod") < 0) {
	perror("ioctl (I_PUSH bufmod)");
	exit (1);
    }

	/* Set the read timeout */
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    si.ic_cmd = SBIOCSTIME;
    si.ic_timout = INFTIM;
    si.ic_len = sizeof timeout;
    si.ic_dp = (char *)&timeout;

    if (ioctl(if_fd, I_STR, (char *)&si) < 0) {
        perror("ioctl (I_STR: SBIOCSTIME)");
        exit (1);
    }

	/* Set the chunk size */
    si.ic_cmd = SBIOCSCHUNK;
    si.ic_len = sizeof chunksize;
    si.ic_dp = (char *)&chunksize;
    if (ioctl(if_fd, I_STR, (char *)&si) < 0) {
        perror("ioctl (I_STR: SBIOCSCHUNK)");
        exit (1);
    }

        /* Set snaplen */
    si.ic_cmd = SBIOCSSNAP;
    si.ic_len = sizeof snaplen;
    si.ic_dp = (char *)&snaplen;
    if (ioctl(if_fd, I_STR, (char *)&si) < 0) {
        perror("ioctl (I_STR: SBIOCSSNAP)");
        exit (1);
    }

        /*
         * Flush the read queue, to get rid of anything that
         * accumulated before the device reached its final configuration.
         */
/* *** Don't do this; there is a kernel bug that effectively sets the
     snaplen to 0 whenever there is an I_FLUSH.
     
    if (ioctl(if_fd, I_FLUSH, (char *)FLUSHR) < 0) {
        perror("ioctl (I_FLUSH)");
        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;
{
    /****  Does not seem to return anything sensible... I suppose it is
                                another NIT bug!
    if (NIT_drops) {
        (void)sprintf(outp, "NIT interface drops= %d\n", NIT_drops);
        return(TRUE);
    }
    ****/

    if (DLPI_drops) {
	(void)sprintf(outp, "DLPI interface drops= %d\n", DLPI_drops);
	return(TRUE);
    }

    return(FALSE);
}
