
/**
 *	Program Name:	nim960 program
 *
 *	Filename:	nim_rcv.c
 *
 *	$Log:   /b/gregs/i960/tcpip/mpd/nim_rcv.c_v  $
 * 
 *    Rev 1.1   30 Jul 1993 13:54:38   franks
 * Internal engineering release
 * 
 *    Rev 1.0   14 Jul 1993 10:15:36   gregs
 * Initial revision.
 * 
 *    Rev 1.5   12 Apr 1993 16:01:38   kenb
 * Added a check for initialization of initp.inited before processing packets.
 * 
 *    Rev 1.4   16 Jun 1992 14:58:06   vinay
 * Nothing is changed except a lank line is deleted
 * 
 *    Rev 1.3   13 May 1992 10:39:06   pvcs
 * No change.
 * 
 *    Rev 1.2   08 May 1992 16:15:06   kwok
 * Put another forever loop to limit the number of packet can be handled
 * to replace the goto statement.
 * 
 *    Rev 1.0   16 Apr 1992 18:25:52   pvcs
 * Initial revision.
 *
 *	Comments:
 *
 *	Copyright (c) 1992 by Hughes LAN Systems
 **/
#include <krnl.h>
#include <types.h>
#include <dbd.h>
#include <netbuf.h>
#include <ether.h>
#include <tcpip.h>
#include <pkt.h>
#include <frame.h>
#include <xlate.h>


#define RCV_OP	00

extern IF_ENTRY	*ifcntrs;

extern	MBOX	ReceiveMbox;
extern	MBOX	IpReceiveMbox;
extern tcpip	*initp;

static	int	MaxPackets = 20;	/* handler at most this many packets 
					in a loop before calling ReSchedule().	*/
/*
 *  ROUTINES TO TRANSLATE FROM FTP TYPE DRIVERS TO THE NIM CHANNEL DRIVER
 */ 

/* 
 * Process received packet:
 *   funnel to TCP/IP.ARP or to V2.
 */
void nim_rcv()
{
	register PKT *d;
	int	ReceivedCount;

	while (_initp->inited == 0)
		ReSchedule();
	/* demultiplexing task body */
	for (;;)
	{
		if( (d = (PKT *)RcvMessage(&ReceiveMbox)) != NULL )  {
		 	ReceivedCount = 0;
			while (ReceivedCount < MaxPackets)
			{
				/*
				 *	We are in the for(;;) loop.
				 *	We have to get the next DBD from the mail box.
				 *	If we have handled "MaxPackets" number of packets, 
				 *	We want to call ReSchedule() to update the watch dog
				 *	timer such that the unit doesn't reset if we stay in
				 *	this loop for ever.
				 */
				if (ReceivedCount != 0)
					if ((d = (PKT *)AcptMessage(&ReceiveMbox)) == NULL)
						break;
				ProcessPacket(d); 
				ReceivedCount++;
			}
			ReSchedule();
		}
	}
}

ProcessPacket(PKT *pkt_ptr)
{
	struct ieeehdr	*e;
	static pktcnt = 0;
	ushort	type;
	DBD	*d;
	ulong saveMask;
	int NotMulti = FALSE;
extern int fault_cnt;
	FlickerLeds(RCV_OP);

	/* May need to adjust packet size to Ethernet minimum, since 
	** frames generated by an FDDI station can be smaller.
	if(pkt_ptr->pktTotalSize < 60) {
		pkt_ptr->pktTotalSize +=  (60 - pkt_ptr->pktTotalSize);	
		pkt_ptr->pktDataSize  =  pkt_ptr->pktTotalSize;	
	}
	*/
	/*
	* convert pkt to dbd
	* assume single pkt
	*/
	if ( (d = (DBD *)snc_get_dbd(pkt_ptr->pktTotalSize)) == NULL )
	{
		/***** MYDEBUG ***/
		enter_debug(0xbad1111, pktcnt);
		/******/
		MaskAllInts(saveMask);
		FreePktBuf(pkt_ptr); 
		RestoreIntMask(saveMask);
		return;
	}
	/***** MYDEBUG *****/
	pktcnt++;
	/******/
	if( pkt_ptr->pktRcvPort == FDDI_PORT_NUM ) {
	fault_cnt = 1;
	printf("Translate\n");
	fault_cnt = 0;
		Translate_fddi_to_eth_stack(pkt_ptr, d);
	}
	else {
		d->db_actcnt = pkt_ptr->pktTotalSize;
		d->db_rcvportno = pkt_ptr->pktRcvPort;
		d->db_indent = 0;
		memcpy(d->db_buffer, pkt_ptr->pktDataPtr, pkt_ptr->pktTotalSize);
	}

	MaskAllInts(saveMask);
	FreePktBuf(pkt_ptr); 
	RestoreIntMask(saveMask);

	/***
	PrintPacket(d->db_buffer, d->db_actcnt);
	***/
	e = (struct ieeehdr *)d->db_buffer;
	/* stats */
	(ifcntrs + d->db_rcvportno)->inbytecnt += d->db_actcnt;
	if (IsMultiCast(d->db_buffer))	/* mcast or bcast */
	{
		(ifcntrs + d->db_rcvportno)->inbmcastpkts++;
	}
	else
	{
		/*
		 *	2.26.92	K Kong
		 *	At boot up time, i.e. bootp, tftp or timep,
		 *	we accept a packet if it's destination address 
		 *	matches any one of my MAC address. During 
		 *	normal working stage, i.e. telnet, ping,
		 *	We should accept those packets with the
		 *	destination address matches my MAC address
		 *	on the receiving port. 
		 *	This should have been done in the packet
		 *	processing. Since we do not want to burden
		 *	the packet processing code, we do the testing
		 *	in here. If it is not for me, do not count
		 *	this as an error or increment the inucastpkts
		 *	counter.
		 */

		if (!IsPacketForMe(d))
		{
			snc_put_dbd(d);
			return;
		}
		(ifcntrs + d->db_rcvportno)->inucastpkts++;
	}

	/* filter protocol */
	if (ntohs(e->i_size) > 1600)
	{
		/* its an ethernet packet */
		switch(e->i_size)
		{
			case ET_TRAILER0:
			case ET_TRAILER1:
			case ET_TRAILER2:
			case ET_IP:
			case ET_ARP:
				/* pass to TCP/IP receiver */

				etarp_rcv(d, 0);/* not using IEEE header */
				return;

			case 0x0460:
				/* pass to LAT receiver */
				lat_rcv(d, 0);	/* not using IEEE header */
				return;

			default:
				break;
		}
	}
	else if (e->i_snp0 == 0xaaaa  &&  e->i_snp2 == 0x03)
	{
		/* its a snap */
		if (e->i_dod0 == 0x00  &&  e->i_dod1 == 0x0000)
		{
			/* its a DOD packet (IEEE tcp/ip) (he filters type) */
			etarp_rcv(d, 1);/* using IEEE header */
			return;
		}
		else if (e->i_dod0 == 0x00 && e->i_dod1 == 0x1000)
		{
			/*
			 *	It's a sytek packet
		 	 */
			if (e->i_type == 0x0100)
			{
				/*
				 *	its V2
				 */
				v2_rcv(d);
				return;
			}
		}
	}
	else if (e->i_snp0 == 0x4242  &&  e->i_snp2 == 0x03)
	{
		/*
		 *	It is a spanning tree protocol
		 */
	 	SendToSTP(d);
		return;
	}

	/* statistic counters */
	/*
	 *	2.11.92	K Kong
	 *	It is an unknown protocol packet
	 *	if the destination address is not multicast
	 */
	if (!IsMultiCast(d->db_buffer))	/* not mcast nor bcast */
		(ifcntrs + d->db_rcvportno)->inunknwnpkts++;
	snc_put_dbd(d);
}

/*
 *	The receiving task for ip packet
 */
void nim_iprcv()

	{
	DBD	*d;

	/* demultiplexing task body */
	for (;;)
		{
		/* get packet */
		d = (DBD *)RcvMessage(&IpReceiveMbox);
		indemux(d, d->nb_len);
		}
	}
PrintPacket(byte *p, int length)

	{
	printf("\n");
	while (length--)
		printf("%x ", *p++);
	printf("\n");
	}

ModifyPacketCount(int count)
	{
	MaxPackets = count;
	}


/********************************************************************
	Translate_fddi_to_eth_stack - translate an FDDI frame to the format
		needed to tx it out on an ethernet port.
********************************************************************/
Translate_fddi_to_eth_stack(pp, dbp)
PKT* pp;			/* PKT ptr for frame to be translated */
DBD* dbp;		/* DBD to be sent up the stack. */
{
	XFRMHDR* fp;		/* ptr to hdr of FDDI frame to be translated */
	FRMHDR* xfp;   /* ptr to hdr of ETH xlation frame */
	word* ap;		/* ptr to addrs in frame after translation shift */
	byte tmp_ln[2];
	int i;

	fp = (XFRMHDR*)((pp)->pktDataPtr );		/* ptr to frame (after FC byte) */
	if( fp->_s == 0xaaaa  &&  ((fp->_n) & 0x00ff) == 0x0003 )	{	/* if SNAP UI */
		/* if 'tunnel' frame or if RFC1042 and protocol type is NOT AARP */
		if( fp->_a == PID_TUNNEL  ||
				(fp->_a == PID_RFC1042  &&  fp->_p != AARP_PT) )
		{
			/* Squeeze out the SNAP subheader by
				shifting the ethernet addresses down to just before the 
				protocol type (the last 2 bytes of the SNAP subheader).
				Note 1: the source and destination areas of this copy
				overlap, so we copy from the end to prevent the data
				from getting clobbered. 
		   */


			ap = (word*)(dbp)->db_buffer;			/* new dst addr */

			for(i=0; i<3; i++)		/* for each word of addr (12 bytes) */
			{
				bitrev.w = *((word*)fp + i);		/* get 4 bytes */
				*((shrt*)ap + (i*2))     = bitrev.s[0];	/* put 4 at new loc */
				*((shrt*)ap + ((i*2)+1)) = bitrev.s[1];	/* put 4 at new loc */
			}

         /* Since data ptr was incremented by one in the packet */
         /* processing code additional increment should be      */
         /* (DELTA_XL - 1)                                      */
			(pp)->pktDataPtr += (DELTA_XL-1)+12;		/* adjust data ptr */

			/* adjust the data ptr and the data length in the PKT structure */
			(pp)->pktTotalSize -= DELTA_XL;		/* ditto... */
			
			if(pp->pktTotalSize < 60)
				pp->pktTotalSize += (60 - pp->pktTotalSize);

			dbp->db_actcnt    = (pp)->pktTotalSize;
			dbp->db_rcvportno = FDDI_PORT_NUM;
			dbp->db_indent = 0;
			memcpy((dbp->db_buffer+12), pp->pktDataPtr,
                                             pp->pktTotalSize-12);
		}
		else    {	/* Translate into an 802.3 style pkt. Need to insert a	*/
						/* len field just after the Source Mac Address				*/
				
			/* Copy the mac header information to the new pkt buffer */
			xfp = (FRMHDR*)(dbp->db_buffer);			/* ptr to frame hdr */

			/* Copy mac addrs (3 words) to stack buffer */ 
			for(i=0; i<3; i++)		/* for each word of addr (12 bytes) */
			{
				bitrev.w = *((word*)fp + i);				/* get 4 bytes */
				*((word*)&xfp->dl + i) = bitrev.w;		/* put 4 at new loc */
			}

			/* Fill in the 802.3 len field in the new pkt buffer.
			** Get the len info from the original fddi pkt.
			*/       
			tmp_ln[0]=(((pp)->pktTotalSize-13)&0xff00) >> 8;/* 13 == FC+DA+SA */
			tmp_ln[1]=(((pp)->pktTotalSize-13)&0x00ff);     /* 13 == FC+DA+SA */
			(xfp->ln) = *((shrt *)&tmp_ln[0]);

			/* Setup some crutial info in the xlate pkt/buff */
			dbp->db_actcnt    = (pp)->pktTotalSize+2-1;		/* 802.3Len - FC */
			dbp->db_rcvportno = FDDI_PORT_NUM;
			dbp->db_indent    = 0;

			/* Adjust the data ptr of the original pkt */
			(pp)->pktDataPtr  += 12;			/* DA+SA , FC - Already done.*/

			memcpy(dbp->db_buffer+14, pp->pktDataPtr,
															pp->pktTotalSize-13);
		}
	}
} /* end Translate_fddi_to_eth_stack() */

