SRI-NOSC/ncpk/dti/impi1.c

#
#include "../h/param.h"
#include "../h/user.h"
#include "../h/buf.h"
#include "../h/net.h"
#include "../h/netbuf.h"
#include "../h/imp.h"
#include "../h/file.h"
#include "../h/ncp.h"
#include "../h/contab.h"
#include "../h/src.h"



/*
	defines for dealing with host to host protocol		*/

#define hhnop	0	/* nop */
#define hhall	4	/* allocate */

/* this array is indexed by the above op codes to give the length of the command */

char hhsize[14]
{
	1,		/* nop */
	10,		/* rts */
	10,		/* str */
	9,		/* cls */
	8,		/* all */
	4,		/* gvb */
	8,		/* ret */
	2,		/* inr */
	2,		/* ins */
	2,		/* eco */
	2,		/* erp */
	12,		/* err */
	1,		/* rst */
	1		/* rrp */
};

/* this array holds the rfnm wait bits for sending allocations to hosts */
char host_map[32];


/*
name:
	imp_iint

function:
	Simply wakes up the input handling process to tell something
	has arrived from the network

algorithm:
	calls wakeup

parameters:

	none


returns:
	i hope so

globals:
	imp_proc

calls:
	wakeup		to start input handling process running

called by:
	hardware

history:
	coded by Steve Holmgren 04/28/75


*/

imp_iint()
{
	wakeup( &imp );
}
/*name:
	imp_input

function:
	Started in response to a wakeup from the input interrupt
	initiates and switches all transfers received from the imp.

algorithm:
	There are two logical states -
	1. The driver will setup an 8 byte read from the imp when
	   it is in the leader state evidenced by impleader != 0
	   even if there is more data to be received from the imp
	   the interface will interrupt and come here for decoding.

	2. After a leader has been received and the endmsg bit of 
	   interface is not sent, the driver falls into a data
	   buffering mode reloaded by ihbget until the endmsg
	   flag is raised.


	if buffering data
		call hh let him handle it
	else
		if leaderread and endmsg means imp to host msg received
			call ih and let him deal with that type
		else
			must be a normal leader with further data waiting in imp
			is imp pad byte != 0
				yes error do stats and flush imp
			else
				legal leader
				if hh protocol msg (imp.link == 0)
					set flag
					continue buffering data
				else
					if host & link number are in conntab
						then set ptr to associated inode
						and continue reading data
					else
						error flush imp 

parameters:
	none

returns:
	nothing

globals:
	impleader=		toggle as to whether doing leader reads
	struct imp		struct for accessing various imp leader fields
	impiptr=		set to addr of user inode

calls:
	hh			to handle hh protocol msgs
	ih			to handle imp to host protocol msgs
	flushimp		to keep reading data until endmsg is on
	ihbget			to reload imp with fresh imp data buffer
	imphostlink		to look host link number up in conn tab return sktp ptr

called by:

history:

	initial coding 1/7/75 by Steve Holmgren
*/


imp_input()	/* imp input handler */
{
	
	/* check of imp error bit */
	if (IMPADDR->istat < 0 && IMPADDR -> iwcnt != 0) /* imp incomplete sets error also */
	{
		printf("IMP error -- resetting\n");
		while( IMPADDR->istat < 0 )
			imp_init();
		return;
	}
	if (impleader == 0)	/* leader read ? */
		hh();		/* no data is being buffered */
	else
	{
		if( IMPADDR->istat & iendmsg ) /* ih msg? */
			ih();	/* yes let him deal with it */
		else
		{		/* host to host leader */
			/* legal leader */
			if( ((imp.type&07) != 0) || (imp.pad1 != 0) )
			{
			iherr:
				impiptr = 0;
				imp_stat.i_leaderr++;
				flushimp();
				return;
			}
			else
			{   /* yes legal leader */
				if (imp.link == 0)	/* hh protocol? */
				{
					impiptr = 0;
				nxtbuf:
					ihbget();
					return;
				}
				/* data read -- we know this guy?? */
				if( impiptr = imphostlink( imp.link & 0177 ))
					goto nxtbuf;	/* got iptr cont reading */
				else
				{
					goto iherr;	/* whos he err */
				}
			}
		}
	}
	
}



/*name:
	hh

function:
	If data received was not an imp leader to continue buffering
	until endmsg is raised on imp interface, once raised, msg is
	switched either to user or passed to hh1 for further decoding
	and possible switching.

algorithm:
	if endmsg raised
		if flushing imp
			discard data 
			reset flushing switch
			if data for user
				indicate error 
				allow him to run
		else
		not flushing so data is either for ncp daemon or user
				decrement users byte allocation by msg size
				link msg to user msg queue
				increment users msg queue byte total
				let user run
			msg is a host to host msg call hh1 for further decoding
		start another leader read
	else
		endmsg not set so either keep buffering or flushing
		if flushing
			keep flushing
		else
			keep reading

parameters:
	none

returns:
	nothing

globals:
	impmsg->b_len=
	impflushing=
	sktp->r_flags=
	sktp->r_bytes=
	sktp->r_msgs=
	sktp->r_msgq
	sktp->r_qtotal=

calls:
	freemsg			to destroy buffer data
	wakeup (sys)		to allow user to run
	bytesout		to destroy first data byte
	rmovepad		to remove imp padding and set length
	to_ncp			to pass data to ncpdaemon
	hh1			for further decoding and switching of data
	impldrd			to start another leader read
	flushimp		to continue flushing data from imp
	ihbget			continue bufferin data
called by:
	imp_input

history:

	initial coding 1/7/75 by Steve Holmgren
	check for something in impmsg 8/16/76 S. Holmgren
	modified to do send events 12/8/76 by David Healy
*/

hh()
{
	register struct rdskt *sktp;
	register struct netbuf *bufp;
	int temp;

	sktp = impiptr;
	if( impmsg )			/* if there is anything in the msg */
		impmsg->b_len = net_b_size;	/* by defination the buffer
						   is either full or the last.
						   if last rmovepad will set
						   length correctly */

	if( IMPADDR->istat & iendmsg)	/* end of msg? */
	{
		if( impflushing ) 		/* finished flushing */
		{
			freemsg( impmsg );	/* destroy any bfred data */
			impmsg = 0;		/* get rid of previous msg */
			impflushing = 0;	/* reset flushing */
			if (sktp)		/* was user proc involved */
			{
				sktp->r_flags =| n_eof;	/* set err */
				if (sktp -> w_flags & n_nbio)
					ipc_trans (SRC_READ | (1 << 8),
						sktp -> r_pid, sktp -> r_ufid, -1);
				else
					wakeup( sktp );
			}
		}
		else
		{
			if( impmsg == 0 )		/* empty msg? */
			{
				printf("zero impmsg\n");
				return;
			}
			if( bytesout( &impmsg,&temp,1,1 ) )
				printf("imp odd byte\n");
			if( rmovepad() )	/* remove padding and set len */
			{
				impldrd();
				return;
			}
			if (sktp)		/* user or hh msg? */
			{
				if( sktp->r_flags&n_toncp)	/* data to ncp? */
					to_ncp(impncp,5,impmsg);
				else	/* no give to user and wakeup */
				{
					/* dec msgs allocated */
					sktp->r_msgs--;
					sktp->r_qtotal =+ implen;
					sktp->r_msgq = catmsg( sktp->r_msgq,impmsg );
					if (sktp -> r_flags & n_nbio)
					{
						if (sktp -> r_flags & n_event)
						{
							ipc_trans (SRC_READ | (1 << 8), sktp -> r_pid,
								sktp -> r_ufid, sktp -> r_qtotal);
							sktp -> r_flags =& ~n_event;
						}
					}
					else
						wakeup( sktp );
				}
			}
			else	/* nope hh msg */
				hh1();		/* let him handle this */
		}
		impldrd();	/* start another leader read */
	}
	else
	if (IMPADDR -> iwcnt == 0) /* how about buffer full then */
	{
		/* not end msg - keep flushing or reading */
		if( impflushing )	/* flushing? */
			flushimp();	/* yes - keep flushing */
		else
			ihbget();	/* no cont reading data */
	
	}
	else
		printf("IMP interface spurious interrupt\n");
}



/*name:
	ih

function:
	To look at all imp to host messages and handle rfnms, incomplete
	transmissions, and nops

algorithm:
	if imp.type is request for next message (rfnm)
		tell user rfnm arrived
	if imp.type is nop
		start another leader read
	if imp.type is error_in_data or incomplete_transmission
		tell user last data he sent is in error or imp couldnt handle
	if imp.type is non of the above
		send imp leader to ncpdaemon for processing

	in any case start another leader read

parameters:
	none

returns:
	nothing

globals:
	imp.type
calls:
	siguser			to let user see rfnms, incomptrans or err data
	to_ncp			to ship leaders to ncpdaemon
	impldrd			to start another leader read

calls:
called by:
	imp_input

history:

	initial coding 1/7/75 by Steve Holmgren
*/

ih()
{
	
	switch( imp.type )
	{
		case ih_rfnm:	siguser( n_rfnm );	/* tell user rfnm arrived  */
		case ih_nop:	break;		/* ignore nops */

		case ih_edata:
		case ih_ictrans:siguser( n_xmterr );	/* tell user about his problem   */
				break;
		default:	to_ncp( impncp,5,0 );	/* send leader to ncp */

	}
	impldrd();		/* start another leader read */
	
}


/*name:
	siguser

function:
	ostensibly to or the parameter into the users flag field and
	let him run. If the socket is closed send a close command
	to the ncp daemon he was waiting for a msg to clear the imp sys
	If the ncp daemon is monitoring all data going to a user send
	the rfnm to him
	if this is a host to host protocol rfnm let the ncp daemon
	know he can now send further protocol msgs to that host.


algorithm:
	If imp.link!=0 andif the host link entry is in the conn tab
		If conn closed
			send close to ncpdaemon
		if data for ncpdaemon
			send leader to ncpdaemon
		else
			or param into flag field
			if got a rfnm
				update msg and bit allocations
			if non blocking i/o
				if event wanted
					send rfnm or xmiterr event
			else
				wakeup user
			turn of waiting and n_event bits
	else
		host to host protocol return response so
		allow ncpdaemon to process 

parameters:
	sigflg		bits to be ored into the users flag field

returns:
	nothing

globals:
	imp.link
	impncp
	conentry->w_flags=

calls:
	imphostlink		to relate host link to socket entry
	wakeup (sys)		to allow user to run
	to_ncp			to send data to ncp daemon

called by:
	ih

history:

	initial coding 1/7/75 by Steve Holmgren
	removed check for rfnm so incomplete transmissions 
	will also reset the host rfnm bit 8/20/76 S. Holmgren
	modified to send completion events 12/8/76 by David Healy
*/

siguser( sigflg )		/* called when user needs waking up. the
				   passed flag is ored into his flag field
				   and he is awakened */
{
	register conentry;
	register src;			/* for sending events */
	register int cnt;		/* for sending events */
	
	if( imp.link != 0 )
	{
		if( (conentry = imphostlink( imp.link | 0200 )) == 0 )
		{
/* 			printf("rfnm on bad link %o %o\n",imp.host,imp.link); /* */
			to_ncp( impncp,5,0 );
			return;
		}
		if( (conentry->w_flags&n_open) == 0 )
			return;
		if( conentry->w_flags & n_toncp )
			to_ncp( impncp,5,0 );	/* give to ncp */
		else
		{
			conentry -> w_flags =& ~n_waiting;
			conentry->w_flags =| (sigflg);	/* set flags */
			if (sigflg & n_rfnm)		/* update allocation? */
			{
				conentry -> w_msgs =- 1;	/* dec msg cnt */
				dpsub (conentry -> w_falloc, conentry -> w_xfalloc); /* and bits */
				conentry->w_xfalloc = 0;
			}
			if (conentry -> w_flags & n_nbio)
			{
				conentry -> w_flags =| n_event;
				src = (sigflg & n_rfnm) ? SRC_WRITE : SRC_NAK;
				if ((cnt = anyalloc (conentry)) || src == SRC_NAK)
				{
					conentry -> w_flags =& ~n_event;
					ipc_trans (src | (1 << 8), conentry -> w_pid, conentry -> w_ufid,cnt);
				}
			}
			else
				wakeup( conentry );
		}
	}
	else
	{
		/* user waiting for control link rfnm? */
		if( bit_on( host_map,imp.host & 0377) != 0 )
		{
			/* say rfnm here */
			reset_bit( host_map,imp.host & 0377);
			/* let any users battle it out */
			wakeup( host_map+(imp.host&0377) );
		}
		else
			/* no users waiting ship to daemon */
			to_ncp( impncp,5,0 );
	
	}
}