
#ifdef SOLARIS

#include <sys/types.h>
#include <sys/stropts.h>
#include <sys/dlpi.h>
#include <sys/bufmod.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <stdio.h>

#include "ifinfo.h"

#define MAXDLBUF 32768
#define MAXWAIT 15

void
sigalrm()
{}

strgetmsg(fd, ctlp, datap, flagsp, caller)
int	fd;
struct	strbuf	*ctlp, *datap;
int	*flagsp;
char	*caller;
{
	int	rc;
	static	char	errmsg[80];

	/*
	 * Start timer.
	 */
	(void) signal(SIGALRM, sigalrm);
	if (alarm(MAXWAIT) < 0) {
	     perror("alarm");
	}

	/*
	 * Set flags argument and issue getmsg().
	 */
	*flagsp = 0;
	if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
	     perror("getmsg");
	}

	/*
	 * Stop timer.
	 */
	if (alarm(0) < 0) {
	     perror("alarm");

	}

	/*
	 * Check for MOREDATA and/or MORECTL.
	 */
	if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA))
	     fprintf(stderr, "%s:  MORECTL|MOREDATA", caller);
	if (rc & MORECTL)
	     fprintf(stderr, "%s:  MORECTL", caller);
	if (rc & MOREDATA)
	     fprintf(stderr, "%s:  MOREDATA", caller);

	/*
	 * Check for at least sizeof (long) control data portion.
	 */
	if (ctlp->len < sizeof (long))
	     fprintf(stderr, "getmsg:  control portion length < sizeof (long):  %d", ctlp->len);
}


dlbindack(int fd, char *bufp)
{
     union DL_primitives *dlp;
     struct strbuf ctl;
     int flags;
     
     ctl.maxlen = MAXDLBUF;
     ctl.len = 0;
     ctl.buf = bufp;
     
     strgetmsg(fd, &ctl, (struct strbuf *)0, &flags, "dlbindack");
     dlp = (union DL_primitives *)ctl.buf;
/*
     expecting(DL_BIND_ACK, dlp);
*/
     if(flags != RS_HIPRI)
	  fprintf(stderr, "dlbindack: DL_BIND_ACK was not M_PCPROTO\n");
     if(ctl.len < sizeof(dl_bind_ack_t))
	  fprintf(stderr, "dlbindack: short response\n");
}



dlokack(int fd, char *bufp)
{
     union DL_primitives *dlp;
     struct strbuf ctl;
     int flags;
     
     ctl.maxlen = MAXDLBUF;
     ctl.len = 0;
     ctl.buf = bufp;
     
     strgetmsg(fd, &ctl, (struct strbuf *)0, &flags, "dlackok");
     dlp = (union DL_primitives *)ctl.buf;
/*
     expecting(DL_OK_ACK, dlp);
*/
     if(flags != RS_HIPRI)
	  fprintf(stderr, "dlokack: DL_OK_ACK was not M_PCPROTO\n");
     if(ctl.len < sizeof(dl_ok_ack_t))
	  fprintf(stderr, "dlokack: short response\n");
}

void
dlpromisconreq(int fd, unsigned long level, char *buf)
{
     dl_promiscon_req_t promiscon_req;
     struct strbuf ctl;
     
     promiscon_req.dl_primitive = DL_PROMISCON_REQ;
     promiscon_req.dl_level = level;

     ctl.maxlen = 0;
     ctl.len = sizeof(promiscon_req);
     ctl.buf = (char *)&promiscon_req;

     if(putmsg(fd, &ctl, (struct strbuf *)0, 0) < 0)
	  perror("putmsg(promisc)");
     else
	  dlokack(fd, buf);
}

dlattachreq(int fd, unsigned long ppa, char *buf)
{
     dl_attach_req_t attach_req;
     struct strbuf ctl;

     attach_req.dl_primitive = DL_ATTACH_REQ;
     attach_req.dl_ppa = ppa;

     ctl.maxlen = 0;
     ctl.len = sizeof(attach_req);
     ctl.buf = (char *)&attach_req;

     if(putmsg(fd, &ctl, (struct strbuf *)0, 0) < 0)
	  perror("putmsg(attach)");
     else
	  dlokack(fd, buf);
}

dlbindreq(int fd, unsigned long sap,
	  unsigned long max_conind, unsigned long service_mode,
	  unsigned long conn_mgmt, unsigned long xidtest,
	  char *buf)
{
     dl_bind_req_t bind_req;
     struct strbuf ctl;
     
     bind_req.dl_primitive = DL_BIND_REQ;
     bind_req.dl_sap = sap;
     bind_req.dl_max_conind = max_conind;
     bind_req.dl_service_mode = service_mode;
     bind_req.dl_conn_mgmt = conn_mgmt;
     bind_req.dl_xidtest_flg = xidtest;
     
     ctl.maxlen = 0;
     ctl.len = sizeof(bind_req);
     ctl.buf = (char *)&bind_req;

     if(putmsg(fd, &ctl, (struct strbuf *)0, 0) < 0)
	  perror("putmsg(bind)");
     else
	  dlbindack(fd, buf);
}

void
getnameppa(char *ifname, char **name, int *ppa)
{
     char *cp;

     *name = ifname;
     *ppa = 0;

     cp = ifname+(strlen(ifname)-1);

     while(isdigit(*cp))
	  cp--;

     cp++;
     if(*cp){
	  int len;
	  *ppa = atoi(cp);

	  len = cp-ifname;
	  if(*ifname != '/')
	       len += 5; /* strlen("/dev/"); */

	  *name = (char *)malloc(len+1);
	  if(*ifname == '/')
	       memcpy(*name, ifname, cp-ifname);
	  else
	       sprintf(*name, "/dev/%s", ifname);
	  (*name)[len] = 0;
     }
}


static struct ifinfo if_fddi = { 7, 6 };
static struct ifinfo if_ether = { 7, 6 };


opennit(char *ifname, int promisc, void (*filter)(int))
{
     int fd;
     long buf[MAXDLBUF];
     struct strioctl ioc;
     struct timeval tmv;
     int csize = (32768/sizeof(unsigned long));
     int ppa;
     char *name;

     getnameppa(ifname, &name, &ppa);

     if((fd=open(name, O_RDWR)) < 0){
	  perror(name);
	  exit(1);
     }
     
     dlattachreq(fd, 0, (char *)buf);


     if(promisc)
	  dlpromisconreq(fd, DL_PROMISC_PHYS, (char *)buf);

     dlbindreq(fd, 0x800, 0, DL_CLDLS, 0, 0, (char *)buf);

     ioctl(fd, DLIOCRAW, 0);

     if(ioctl(fd, I_PUSH, "pfmod") < 0){
	  perror("pfmod push");
     }

     (*filter)(fd);

     tmv.tv_sec = 1;
     tmv.tv_usec = 0;
     if(ioctl(fd, I_PUSH, "bufmod") < 0){
	  perror("bufmod push");
     }

     ioc.ic_cmd = SBIOCSTIME;
     ioc.ic_timout = -1;
     ioc.ic_len = sizeof(struct timeval);
     ioc.ic_dp = (char *)&tmv;
     if(ioctl(fd, I_STR, &ioc) < 0){
	  perror("timestamp set");
     }

     ioc.ic_cmd = SBIOCSCHUNK;
     ioc.ic_timout = -1;
     ioc.ic_len = sizeof(unsigned int);
     ioc.ic_dp = (char *)&csize;
     if(ioctl(fd, I_STR, &ioc) < 0){
	  perror("chunksize set");
     }
     
     ioctl(fd, I_FLUSH, (char *)FLUSHR);

     return fd;
}

void
procpkts(int fd, void(*handler)())
{
     unsigned long databuf[(65536*2)/sizeof(unsigned long)];
     struct strbuf data;
     int i;
     int flags;

     data.buf = (char *)databuf;
     data.maxlen = sizeof(databuf);
     data.len = 0;
     flags = 0;

     while(getmsg(fd, 0, &data, &flags) >= 0){
	  if(data.len > 0){
	       char *p, *limp;;
	       limp = data.buf + data.len;
	       for(p=data.buf;p<limp;){
		    struct sb_hdr *bp = (struct sb_hdr *)p;
		    char *data = p + sizeof(struct sb_hdr);
		    (*handler)(data,
			       bp->sbh_msglen,
			       bp->sbh_timestamp);
		    p += bp->sbh_totlen;
	       }
	  }
	  data.buf = (char *)databuf;
	  data.maxlen = sizeof(databuf);
	  data.len = 0;
	  flags = 0;
     }
     perror("getmsg");
}

#endif
