#include "pcdefs.h"
#include "mbuf.h"
#include "protocol.h"
#include "funcdef.h"
#include "../defs.h"

struct mbuf _near *mbfree, _near *mbprocess, _near * _near *mbnext;
struct mbuf mb[NMBUFS];
struct ebuf eb[NEBUFS+1] = { 0 };
unsigned char etherbuff[RAWETHER];

int slip_mode, pktclass;
extern int neterrno;

static int	ip_handle = 0;
static int	arp_handle = 0;
static int	rarp_handle = 0;

#define IC_ETHERNET	1
#define IC_SLIP		6
#define	IT_ANY		0xFFFF

#define set_rcv_mode(a,b)

u_char etherall[DADDLEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
u_char myether[DADDLEN];

static u_short _near locate_pkt_vector(u_short);

static u_short _near
locate_pkt_vector(vec)             /* search for the packet driver */
u_short	vec;
{
	u_char _far *vptr;

	if (vec == 0) {
	    for (vec = 0x60; vec < 0x80; vec++) {
		vptr = *(u_char _far * _far *)(unsigned long)(vec << 2);
		if (!memcmp(vptr + 3, (u_char _far *)"PKT DRVR", 8)) {
			patch_vec((u_char)vec);
			return 0;
		}
	    }
	    neterrno = NETERR_NOTLOADED;
	    return -1;
	} else if (vec < 0x60 || vec > 0x7f) {
	    neterrno = NETERR_BADARGS;
	    return -1;
	} else {
	    vptr = *(u_char _far * _far *)(unsigned long)(vec << 2);
	    if (memcmp(vptr + 3, (u_char _far *)"PKT DRVR", 8)) {
		neterrno = NETERR_NOTLOADED;
		return -1;
	    }
	    patch_vec((u_char)vec);
	    return 0;
	}
}

char _near iptype[] = {8, 0};
char _near arptype[] = {8, 6};
char _near rarptype[] = {0x80, 0x35};
/*
 *	pkopen()
 *	try and locate the packet driver,
 *	open ARP and IP handles.
 */
int _near
pkopen(address, ioaddr, flags)
u_short	address;	/* address is packet class */
u_short	ioaddr;		/* packet int, or 0 */
u_char flags;		/* RARP? */
{
	struct packet_info p;
	int	i;
	struct mbuf *mp;

	mbfree = NULL;
	mbprocess = NULL;
	mbnext = &mbprocess;
	mp = mb;
	for (i = 0; i < NMBUFS; i++) {
		mp->next = mbfree;
		mbfree = mp++;
	}
	eb[0].start_addr = etherbuff;
	eb[0].count = sizeof etherbuff;

	if (ip_handle)
		return 0;

	if (locate_pkt_vector(ioaddr)) {
		neterrno = NETERR_NOTLOADED;
		return -1;
	}

	if (driver_info(&p)) {
		neterrno = NETERR_SYSTEM;
		return -1;
	}

	if (address && address != p.packet_class) {
		neterrno = NETERR_NOSUPPORT;
		return -1;
	}

	if (p.packet_class != IC_ETHERNET && p.packet_class != IC_SLIP) {
		neterrno = NETERR_NOSUPPORT;
		return -1;
	}

	pktclass = p.packet_class;
	slip_mode = pktclass == IC_SLIP;

	ip_handle = access_type(pktclass, IT_ANY, 0, iptype,
		slip_mode ? 0 : sizeof(iptype), pkt_receiver);
	if (ip_handle < 0) {
		ip_handle = 0;
		neterrno = NETERR_ADDRINUSE;
		return -1;
	}
	set_rcv_mode(ip_handle, 3);
	if (!slip_mode) {
		arp_handle = access_type(pktclass, IT_ANY, 0,
			arptype, sizeof(arptype), pkt_receiver);
		if (arp_handle < 0) {
			(void) release_type(ip_handle);
			ip_handle = 0;
			arp_handle = 0;
			neterrno = NETERR_ADDRINUSE;
			return -1;
		}
		set_rcv_mode(arp_handle, 3);
		if ((i = get_address(ip_handle, myether, 6)) < 0) {
			(void) release_type(ip_handle);
			ip_handle = 0;
			(void) release_type(arp_handle);
			arp_handle = 0;
			neterrno = NETERR_SYSTEM;
			return -1;
		}
		if (flags & H_RARP) {
		    rarp_handle = access_type(pktclass, IT_ANY, 0,
			    rarptype, sizeof(rarptype), pkt_receiver);
		    if (rarp_handle < 0) {
			(void) release_type(ip_handle);
			(void) release_type(arp_handle);
			ip_handle = 0;
			arp_handle = 0;
			rarp_handle = 0;
			neterrno = NETERR_ADDRINUSE;
			return -1;
		    }
		    set_rcv_mode(rarp_handle, 3);
		}
	}
	return 0;
}

void _near
pkclose()                     /* throw away our handles */
{

	if (!slip_mode) {
		set_rcv_mode(arp_handle, 1);
		(void) release_type(arp_handle);
		if (rarp_handle) {
			set_rcv_mode(rarp_handle, 1);
			(void) release_type(rarp_handle);
		}
	}
	set_rcv_mode(ip_handle, 1);
	(void) release_type(ip_handle);
}
