#define LOGF 5 /*temporarily here until final assignment is made*/ #include "param.h" #include "file.h" #include "buf.h" #include "net_netbuf.h" #include "user.h" #include "net_net.h" #include "net_ncp.h" #include "inode.h" #include "net_contab.h" #ifdef SCCSID /* SCCS PROGRAM IDENTIFICATION STRING */ char id_ncpio[] "~|^`ncpio.c\tV3.9E2\t09Mar78\n"; #endif extern imp; int ncptimo; /* flag indicating timeout has occurred */ int wf_send (); int wf_setup (); int wf_mod (); int wf_ready (); int wf_clean (); int wf_reset (); int wf_frlse (); int wf_stimo (); /**/ /*NOTE: this struct must match struct kw in kwrite.h, since data is being passed in it. These will soon be combined into one .h file used by both kernel and daemon. */ struct { /*structure data from ncp gets put into*/ char opcode; /*chosen from ncp->kernel op codes*/ char i_index; /*inode index of particular inode in file*/ struct netfile *id; /*file pointer*/ char host; /*eight-bit host number*/ char link; /*eight-bit link number*/ char status; /*various status bits, usually for inode*/ char bytesize; /*network connection bytezise*/ /*following are generated by ncp write routine common preliminaries*/ char *iptr; /*network inode pointer for this file and index*/ } ncprs; /*ncp read structure*/ /*state variables for ncp io routines*/ int ncpdlost; /*data heading for ncp was lost. count of lost messages*/ int ncpopnstate; /*current state of ncp's io channel. 0=closed,>0=open*/ int rootdev; /* same as rootdev dec in ../systm.h */ /* the queues of data destined for the ncp. ncpirq is examined first */ struct netbuf *ncprq; /* non-interrupt traffic for the ncp */ struct netbuf *ncpirq; /* interrupt (priority) traffic */ /*name: ncpopen function: called in response to an open on /dev/ncpkernel initializes the kernel net buffer system and the imp interface algorithm: is ncpkernel already open( only one person may have this open ) determine how many system buffers to initially get( standard is one ) get them and load them into the free list for usable buffers set the state to open initialize the imp parameters: none returns: a file descriptor to be used in further communication with ncpkernel globals: ncpopnstate= net_b.kb_lowat calls: getkb impopen called by: in response to an open on ncpkernel history: initial coding 1/7/75 by S. R. Bunch parameters set up for hysteresis buffering 6 Sep77 J.S.Kravitz */ ncpopen() /*ncp open routine*/ { if(ncpopnstate){u.u_error = ENCP2;return;} /*already open?*/ /*The following two lines modified 6Sep77 by J.S.Kravitz for hysteresis buffer freeing algorithm */ net_b.b_hyster = init_b_hyster; /*setup net buffer surplus*/ while(net_b.b_alloc < init_b_hyster) getkb(); ncpopnstate++; /* mark us open */ impopen(); /* bring up the imp */ } /*name: ncpclose function: to make the network go away algorithm: say noone has this open if there is anything in the input queues, empty them wakeup the input process so it can die. parameters: none returns: nothing globals: ncpopnstate= ncpirq= ncprq calls: freemsg called by: in response to a close on ncpkernel history: initial coding 1/7/75 by S. R. Bunch modified by mark kampe to wake up the input process. HMR stuff removed by greep for Rand interface */ ncpclose() /*ncp close routine*/ { spl_imp(); /* make sure interrupts not doing anything */ /*flush ncp-destined data. since we're marked closed, none will be subsequently added*/ if (ncpirq || ncprq) /* either q nonempty? */ { ncpdlost ++; /*mark some data lost*/ freemsg(ncpirq); /*empty interrupt q*/ freemsg(ncprq); /*empty non-int q*/ ncpirq=ncprq=0; /*as they should be*/ } spl0(); /* let the world back int */ ncpopnstate = 0; /* tell imp daemon we are down */ wakeup( &imp ); } /*name: ncpread function: to pass data from user processes and the network to the ncpdaemon algorithm: if there is anything in the interrupt loaded queue use it otherwise use the non interrupt queue ( note: since the input side is now driven off a kernel process, the distinction between queues can probably be dropped see if there is anything on the normal read queue if so use that else wait for something to come in transfer a full message into the ncpdaemon space delink a message from the queue( for speed ) copy that message into the ncpdaemon's address space if ncpdaemon didnt read a whole message signal and error parameters: u.u_base u.u_count returns: an instruction for the ncpdaemon to munch on globals: ncpirq ncprq calls: sleep ifreebuf( delinkbuf ) catmsg bytesout freemsg called by: in response to a read on ncpkernel history: initial coding 1/7/75 by S. R. Bunch check for timeout added by greep */ ncpread() { register struct netbuf *bufptr; register *qptr; struct netbuf *msgptr; msgptr = 0; /*becomes a logical message*/ check_q: /*examine the two queues*/ spl6(); /* lock out clock interrupts */ if(ncptimo) /* check for timeout first */ { passc(ncp_timo); /* send timeout op code */ ncptimo = 0; /* clear flag (ignore multiple */ return; /* timeout requests */ } if(ncpirq) { spl_imp(); /* can 'reduce' priority to that of imp now */ qptr = &ncpirq; /*priority q non-empty*/ } else { if(ncprq) { qptr = &ncprq; /*regular q non-empty*/ spl0(); /*don't need to lockout this one*/ } else { sleep(&ncprq,1); /*wait until nonempty*/ goto check_q; /*go try again*/ } } /* * may still be at prio imp at this point - * copy first logical message to a temporary message, * then move that to user space */ do { bufptr = (*qptr)->b_qlink; /* first buffer in message */ *qptr = ifreebuf(*qptr); /*remove it from message*/ msgptr = catmsg(msgptr,bufptr); /* append to message*/ } while (( bufptr->b_resv&b_eom) == 0 && *qptr); /*while not last buffer*/ spl0(); /*just in case we were at prio 6*/ u.u_count = bytesout(&msgptr,u.u_base,u.u_count,u.u_segflg); if( msgptr ) /* is msg empty */ { /*ncp didn't read it all. that's a nono*/ u.u_error = ENCPIO; /*io error*/ /*formerly EIO*/ freemsg(msgptr); /*reclaim the space remaining*/ } } /*name: ncpwrite function: to decode and control instructions sent down from the ncpdaemon to embody the ncpdaemons manipulation of the kernel and the network algorithm: determine at least how much the ncpdaemon must always be writing is there that much no return error copy down the header information associated with the instruction (see ncprs) is the opcode legal? is the count within bounds? no return error is there a file associated with this instruction yes is it in the file table no the return error is there a specific inode associated with this instruction? and is it there no return error call the procedure as directed by the daemon( see the wants array above) return any error associated with the instruction parameters: u.u_base(cpass) u.u_count(cpass) returns: either an error or zero globals: ncprs= maxncpwcode u.u_count= wants ncpoptab calls: cpass( sys ) log_to_ncp to log error message timeout( sys ) wf_send( thru ncpoptab ) wf_setup( thru ncpoptab ) wf_mod ( thru ncpoptab ) wf_ready( thru ncpoptab ) wf_clean( thru ncpoptab ) wf_reset( thru hcpoptab ) wf_timo ( thru ncpoptab ) called by: in response to a write on ncpkernel history: initial coding 1/7/75 by S. R. Bunch modified 3/3/76 M. Kampe check ncprs.id = 0 modified 7/8/76 S. Holmgren to check for ncprs.id & FNET modified 1/28/77 by S. M. Abraham to fix bug.... ncprs.id & FNET change to (ncprs.id->f_flag & FNET) and (ncprs.i_index >3) change to (ncprs.i_index > 2) modified by greep to read timeout request from daemon modified 12Jun77 by JSKravitz to re-arrange ncp-op-table to be a array of structure elemements at the suggestion of SMAbraham */ #define want_id 01 /*if set, id parameter is verified before function called*/ #define want_inodep 02 /*if set, presence of an inode pointer at the given index into file is verified*/ #define maxncpwcode 7 /* # of entries in ncpotab */ /*the function routines called by the op code of a downward command*/ int wf_send(), wf_setup(), wf_mod(), wf_ready(), wf_clean(), wf_reset(), wf_frlse(), wf_stimo(), ; struct ncpoptable { int (*ncpopproc)(); int ncpopwants; int ncpopsizes; } ncpoptable [] {&wf_send, 0, 4 /* send data to the network */ ,&wf_setup, want_id, 6 /* get and inode from the sys and attach it to a file */ ,&wf_mod, want_id +want_inodep, 6 /* modify an existing inode/socket */ ,&wf_ready, want_id, 0 /* let a user waiting on a file know something happened */ ,&wf_clean, 0, 0 /* clean up an inode/socket */ ,&wf_reset, 0, 0 /* clean up everything know about a host */ ,&wf_frlse, want_id, 0 /* ncpdaemon is done using a particular file */ ,&wf_stimo, 0, 2 /* set timeout */ }; ncpwrite() { register int i,j; /*counters, temporaries*/ register char *p; /*pointer into ncprs*/ i = &ncprs.bytesize - &ncprs.opcode; /*length of common prelude*/ i++; /* add one to get right count */ if(u.u_count < i) /*is there enough there?*/ { freturn: u.u_error = ENCPINV; /*invalid parameter*/ /*was EINVAL*/ return; } p = &ncprs; /*points to first byte of ncprs*/ for(;i>0;i--)*p++ = cpass(); /*fill ncprs*/ i = ncprs.opcode; /*function to perform*/ if(i<0 || i>maxncpwcode || u.u_count < ncpoptable[i].ncpopsizes) { log_to_ncp("ncpwrt:id"); goto freturn; /*is opdode any good?*/ } if(ncpoptable[i].ncpopwants&want_id && ((ncprs.id == 0) || (infiletab(ncprs.id) == 0) || (ncprs.id->f_flag & FNET == 0))) { log_to_ncp("ncpwrt:index"); goto freturn; /*he wants the id to be good and it isnot*/ } if(ncpoptable[i].ncpopwants&want_inodep && ((ncprs.i_index > 2) || ((ncprs.iptr=ncprs.id->f_netnode[ncprs.i_index]) == 0))) goto freturn; /*inode or index wrong*/ /*invoke the guy*/ u.u_error = (*ncpoptable[i].ncpopproc)(); return; } /*name: to_ncp function: when given a vector a length and a message( the first or the last may be zero ) it sticks the vector on the front of the message and links it into the ncpdaemon's read queue algorithm: is the ncpdaemon still functioning? no say data lost free the message, and return error if the vector is there and will fit in the front of the message move the data back and insert the vector otherwise build a new message with the vector in it concatonate the newmessage with the one passed set the end of message bit in the last buffer of the message link it into the correct queue wakeup anyone waiting on the queue return no error parameters: vec - address of 'len' number of chars to add to the front to msgpp( may be zero ) len - number of chars in vec ( may be zero only if vec is ) msgpp - pointer to a message to be added to ( may be zero ) returns: zero success minus one on ncpdaemon not running one on resources failure globals: ncpdlost ncpirq ncprq calls: freemsg vectomsg catmsg wakeup(sys) called by: hh siguser hh1 allocate netopen daecls history: initial coding 1/7/75 by S. R. Bunch UCBUFMOD additions 19Feb78 by Greg Noel: split code into two routines, modified logic. */ #ifndef UCBUFMOD to_ncp(vec,len,msgpp) /*len and msgpp must not both be zero*/ char *vec; /* returns : 0 = ok, >0 nospace, 0< = ncp not open */ int len; struct netbuf *msgpp; { register struct netbuf *msgp; register char *p; register int l; struct netbuf *newmsg; int *qmsg; msgp = msgpp; if(ncpopnstate <= 0) { ncpdlost++; freemsg(msgp); /* no harm if msgp == 0 */ return(-1); /*ncp has closed. flush data*/ } newmsg = 0; /*will become the data in vec*/ while(len > 0) /*copy integrals of net_b_size into a new message, and as many as possible into the first buffer of the old one*/ { if(msgp) /*is there a first buffer?*/ { if(( l = (len+(msgp->b_qlink)->b_len)) <= net_b_size) /* will it fit in first buffer */ { (msgp->b_qlink)->b_len =+ len; /* set new length of buffer */ p = (msgp->b_qlink)->b_data; /* first byte of data in first buffer */ for(;l>len;l--) p[l-1] = p[l-len-1]; /*move it down*/ for(;len>0;len--) *p++ = *vec++; /*move in vec*/ break; } } if(vectomsg(vec,l=min(net_b_size,len),&newmsg,1)) /* did it do it? */ { freemsg(newmsg); /*not successful. free what it did*/ return(1); /*simple failure*/ } len =- l; /*decr. total length*/ } msgp = catmsg(newmsg,msgp); /*put stuff from vector on front of msg*/ msgp->b_resv =| b_eom; /*mark last buffer*/ qmsg = PS->integ & 0340 ? &ncpirq : &ncprq; /*appropriate q pointer*/ if( *qmsg ) /* anything en-queued */ { newmsg = *qmsg; /* link msgs then */ p = newmsg->b_qlink; /* sav addr of first buf */ newmsg->b_qlink = msgp->b_qlink; /* point last to first */ msgp->b_qlink = p; /* point last to first */ } *qmsg = msgp; /* update msg queue */ wakeup(&ncprq); /*wake up ncp*/ return(0); /*alls well that ends well+*/ } #endif UCBUFMOD #ifdef UCBUFMOD to_ncp(vec,len,msgpp) /*len and msgpp must not both be zero*/ char *vec; /* returns : 0 = ok, >0 nospace, 0< = ncp not open */ int len; struct netbuf *msgpp; { if(ncpopnstate <= 0) { ncpdlost++; freemsg(msgpp); return(-1); /*ncp has closed. flush data*/ } if(msg_q(PS->integ & 0340 ? &ncpirq : &ncprq, /*appropriate q pointer*/ vec, len, msgpp)) return(1); wakeup(&ncprq); /*wake up ncp*/ return(0); /*alls well that ends well+*/ } /* This code defines the msqq structure, which is just a list of messages strung together with the b_eom bit set on the last buffer of a message. This code optimizes the common case of a short vector being placed in front of a short message and leaves the other cases to the general-purpose code. */ msg_q(qmsg, vec, len, msgpp) /* prepends vec of length len to message at msgpp, */ struct netbuf **qmsg; /* then adds it to the queue of messages at qmsg */ char *vec; /* returns : 0 = ok, >0 nospace */ int len; struct netbuf *msgpp; { register struct netbuf *msgp; register char *p; register int l; struct netbuf *newmsg; int bufloc; msgp = msgpp; /* do both exist and will vec fit in first buffer of msg? */ if(len) if(msgp && (l = msgp->b_qlink->b_len+len) <= net_b_size) { msgp->b_qlink->b_len =+ len; /* set new length of buffer */ bufloc = msgp->b_qlink->b_loc; while(--l>=len) /* shift buffer over to give room */ sbbyte(bufloc, l, fbbyte(bufloc, l-len)); for(p=0;l-->=0;) /* move vector in front */ sbbyte(bufloc, p++, *vec++); } else { /* vector exists; make it a message and put on front */ newmsg = 0; /*will become the data in vec*/ if(vectomsg(vec,len,&newmsg,1)) { /* did it do it? */ freemsg(newmsg); /*not successful. free what it did*/ return(1); /*simple failure*/ } msgp = catmsg(newmsg,msgp); /*put stuff from vector on front of msg*/ } msgp->b_resv =| b_eom; /*mark last buffer*/ if( *qmsg ) /* anything en-queued */ { newmsg = *qmsg; /* link msgs then */ p = newmsg->b_qlink; /* sav addr of first buf */ newmsg->b_qlink = msgp->b_qlink; /* point last to first */ msgp->b_qlink = p; /* point last to first */ } *qmsg = msgp; /* update msg queue */ return(0); } #endif UCBUFMOD /*name: log_to_ncp function: Send a null-terminated character string to the NCP daemon to be logged. algorithm: Calculate the length of the length of the string (including the null at the end) plus one. Construct a message with a junk byte at the front. If the message construction was unsuccessful Clean up Say we lost a message to the NCP otherwise Change the junk byte in the message to the LOG opcode (doing it this way avoids a lot of character shuffling). Send it to the NCP. returns: I hope so. globals: ncpdlost= to indicate a message for the NCP was lost. calls: vectomsg to construct a message from a string to_ncp to send the message to the NCP called by: anybody that has something to say. history: initial coding 8/2/77 by J. G. Noel UCBUFMOD additions 19Feb78 by Greg Noel */ log_to_ncp(msg) char *msg; { register char *msgp; struct netbuf *newmsg; for(msgp = msg; *msgp++;); /* find end of string */ newmsg = 0; if(vectomsg(msg-1, (msgp-msg)+1, &newmsg, 1)) { freemsg(newmsg); ncpdlost++; } else { #ifndef UCBUFMOD (newmsg->b_qlink)->b_data[0] = LOGF; #endif UCBUFMOD #ifdef UCBUFMOD sbbyte((newmsg->b_qlink)->b_loc, 0, LOGF); #endif UCBUFMOD to_ncp(0, 0, newmsg); } } /*name: wf_send function: send data to the network ( ncpdaemon takes care of its own leaders ) algorithm: call sndnetbytes parameters: u.u_base - the address of the data to send u.u_count - the number of bytes to send returns: zero globals: u.u_base= u.u_count= calls: sndnetbytes called by: ncpwrite thru ncpoptab history: initial coding 1/7/75 by S. R. Bunch */ wf_send() { /*we enter with u.u_count and u.u_addr set correctly*/ sndnetbytes( u.u_base,u.u_count,0,0,0 ); u.u_count = 0; return( 0 ); } /*name: wf_reset function: to clean up all table entries and processes referencing a specific host. algorithm: thru the whole file table if there is an entry and FERR not set for each inode in the the entry is it in use by the ncp and either the host is zero meaning all or the host matches the one sent down by the daemon. do an iclean on the inode parameters: ncprs.host returns: zero globals: file_tab calls: iclean called by: ncpwrite thru ncpoptab history: modified 6/25/76 by S. F. Holmgren to check for FERR not on in file flag field. */ wf_reset() { register int fp,ip,i; int fpi; for(fpi=0;fpi<FILSIZE;fpi++) /*once for each possible file*/ /* slot in use and FERR not set (uses f_rdnode to pass err info) */ if( ((fp=file_tab[fpi]) != 0) && ((fp->f_flag&FERR) == 0) ) { for(i=0;i<3;i++) /*for each possible inode in file*/ if((ip=fp->f_netnode[i]) /*check for nonzero inode pointer*/ && ip->w_flags&n_ncpiu /*and ncp using inode*/ &&(( ncprs.host == 0) /*and either host is zero*/ || ncprs.host == (ip->w_hostlink).hibyte)) /*or host is same as inde's*/ /* do a clean on the inode */ { fp->f_flag =| FERR; iclean( fp,i ); } } return(0); } /*name: wf_clean function: to either initiate the release or to release the socket( inode ) denoted by ncprs.id and ncprs.index algorithm: if the user still thinks the inode is usable, advise him that he is wrong and send a close to the ncpdaemon. otherwise destroy the inode parameters: ncprs.id - a pointer to a file containing the inode ncprs.index - index into the file for a pointer to the inode returns: zero globals: none calls: iclean iclean calls: wakeup daedes called by: ncpwrite thru ncpoptab ( opcode #4 ) history: initial coding 1/7/75 by S. R. Bunch modified 3/3/76 M. Kampe check non-zero fp call tsrvclean to implement server telnet modified by greep to remove connection table entry removed call on tsrvclean to delete server telnet test JSK 12Jun77 */ wf_clean() { return(iclean(ncprs.id,ncprs.i_index)); /*needed it elsewhere also*/ } iclean(fp,index) struct netfile *fp; /*file pointer*/ int index; /*should be from 0 - 2 */ { register struct wrtskt *ip; /*socket inode pointer*/ if( fp && infiletab( fp ) && ( ip = fp->f_netnode[index] ) ) { /* remove entry from appropriate connection table */ rmcontab( incontab( ip->r_hostlink,ip ) ); ip->r_hostlink = 0; /* show it is gone */ daecls( fp,index ); if(ip->w_flags&n_usriu) /*user still using it?*/ { fp->f_flag =| FERR; ip->w_flags =& ~(n_ncpiu |n_open); /*ncp not using it any more*/ ip->w_flags =| n_eof; /*set end-file bit*/ wakeup( ip ); } else /* both thru, destroy it */ daedes( fp,index ); } return(0); /*no eror we know of*/ } /*name: wf_ready function: to wakeup anyone waiting on a file and advise them of a change in state. algorithm: if there was an error is it a legal error signal the error wakeup anyone waiting on the address parameters: ncprs.id ncprs.status returns: zero if any error indication was requested correctly otherwise invalid parameter globals: ncprs.id ncprs.status calls: wakeup called by: ncpwrite thru ncpoptab( opcode #3 ) history: initial coding 1/7/75 by S. R. Bunch lines commented out by greep to avoid daemon getting write errors - what are these lines supposed to do? 14Jun77 Commented out lines re-installed, but added and rearranged to make sense. J.S.Kravitz 14Jun77 FOPEN in file flags set so that sleep in netopen can figure out that the wfready happenned. J.S.Kravitz 20Apr78 net_frlse moved here in err part to correct a bug in netopen J.S.Kravitz */ wf_ready() { register struct netfile *fp; /* pointer to file struct */ int retval; retval = 0; fp = ncprs.id; /* pointer to net file struct */ if( ncprs.status ) /* was there an error */ { fp->f_flag =| FERR; /* signal error happened */ /* * if the read-inode pointer is non-zero, then this * constitutes an error in the state machine of the * file machine in the ncpdaemon. This code correctly * notifies the ncpdaemon of this. In this case, it is * probably undesirable to try to get this file descritor * back to the system, but we will notify the user anyway * JSK */ if (fp->f_netnode[f_rdnode]) { /* this should be zero */ retval = ENCPINV; /*was EINVAL*/ }else{ fp->f_netnode[f_rdnode] = ncprs.status; /* return err val */ } /* * decrement use count and remove file table entry */ /*net_frlse (fp); I think this is wrong.... /JGN */ }else{ fp->f_flag=| FOPEN; /* so user knows we did the wakeup */ } wakeup (fp); /* cause user to return from open */ return (retval); /* tell ncp daemon what happenned */ } /*name: wf_inc_alloc function: internal routine to increment the allocation of an inode Can be directly invoked by ncpwrite but isnt algorithm: copy the next six bytes associated with u.u_base & u.u_count if it is greater than 4k bytes return error is this a net or daemon originated allocation ( can be net orginated if first allocation comes in over link zero for a socket and it isnt in the connection table yet hence it goes up to the daemon and down through here ) increment message allocation increment the number of bytes allocated( may be in either bits or bytes) parameters: ncprs.iptr returns: invalid param if allocation is over 4k bits zero if all is well globals: ncprs.iptr ref. socket->r_msgs ref. socket->w_falloc ref. socket->r_bytes calls: log_to_ncp dpadd( sys ) wakeup( sys ) called by: wf_mod wf_setup history: initial coding 1/7/75 by S. R. Bunch */ wf_inc_alloc() { register int i; register char *p,*ip; int alloc[3]; p = &alloc[0]; /*to assemble some bytes into*/ ip = ncprs.iptr; /*inode who gets the allocation*/ for(i=6;i>0;i--) *p++ = cpass(); /*get the bytes into array alloc*/ ip->r_msgs =+ alloc[0]; /*message alloc*/ /* net or daemon orginated allocation */ if( ncprs.link & 0200 ) { /* net originated - kept in bits */ ip->w_falloc[0] =+ alloc[1]; /* add high order word */ dpadd( ip->w_falloc,alloc[2] ); /* add rest */ wakeup( ip ); /* tell user */ } else /* daemon originated pertains to read skt then */ ip->r_bytes =+ (alloc[2]>>3); return(0); /*no error*/ } /*name: wf_mod function: called to modify the state of a socket and to increment the socket allocation if applicable. algorithm: set or reset n_toncp or n_open according to ncprs.status set the hostlink entry of the socket from its contab entry set the bytesize increment any allocation copy any new socket information down parameters: ncprs.iptr ncprs.host and link ncprs.bytesize possibly three allocation words passed to wf_inc_alloc possibly three socket information words for wf_update_skt returns: 0 globals: see parameters calls: incontab wf_inc_alloc wf_update_skt called by: ncpwrite thru ncpoptab (opcode #2) history: initial coding 1/7/75 by S. R. Bunch modified 4/16/76 S. F. Holmgren added socket information */ wf_mod() { register int *ip,*p; /*inode pointer, temporary*/ ip = ncprs.iptr; /*for speed*/ /*change flags*/ ip->w_flags =& ~(n_toncp | n_open); /*clear accessable bits*/ ip->w_flags =| (ncprs.status & (n_toncp | n_open)); /*and set them*/ /*change hostlink*/ /* look in correct connection table for possible error */ if( (p = incontab( ip->w_hostlink,ip )) ) ip->w_hostlink = *p = swab( (&ncprs.host)->integ ); /*change bytesize*/ ip->w_bsize = ncprs.bytesize; /*increment allocation*/ wf_inc_alloc(); /* modify socket information */ wf_update_skt( p ); return( 0 ); } /*name: wf_setup function: ncpwrite write function to initialize a socket inode algorithm: if inode already there or link not 0177 or in contab return error loop thru the inode table and find a free one set ilock so update doesnt write it out to disk say two people are using ncpdaemon and user say its allocated and a special dev set dev and ino to something not usable by sys if cant find inode return error make entry in connection table make entry in file table increment count of people that have file open initialze fields of socket part to passed params parameters: ncprs.iptr ncprs.id= ncprs.host and link ncprs.status ncprs.bytesize returns: 0 globals: see parameters calls: swab incontab entcontab log_to_ncp wf_inc_alloc wf_update_skt called by: ncpwrite thru ncpoptab( opcode #1 ) history: initial coding 1/7/75 by S. R. Bunch modified 4/16/76 by S. F. Holmgren to handle socket information */ wf_setup() { register struct inode *ip; /*incode pointer */ register int *i,hl; /*temporary, hostlink+*/ i = &(ncprs.id->f_netnode[ncprs.i_index]); hl = swab( (&ncprs.host)->integ ); /*get an inode*/ for( ip = &inode[0]; ip < &inode[NINODE]; ip++ ) if( ip->i_count == 0 ) { /* inode free take it */ spl6(); ip->i_flag = ILOCK; /* stay in core */ ip->i_count = 2; /* set people using */ ip->i_mode = IALLOC|IFCHR; ip->i_nlink = 1; /* say some using */ ip->i_dev = ip->i_number = -2; ip->i_lastr = -1; spl0(); goto goti; } /* no available inodes */ log_to_ncp("Ncp Setup: No free inodes"); return( ENFILE ); goti: /* here if we got an inode */ /* pt at i_addr part for storing network data */ ip = &ip->i_addr[0]; /*fill in file pointer*/ ncprs.iptr = ncprs.id->f_netnode[ncprs.i_index] = ip; /*flags, bytesize,allocation*/ ip->w_hostlink = hl; ip->w_flags = (ncprs.status & (n_open | n_toncp)) | n_ncpiu; ip->w_bsize = ncprs.bytesize; /* clear messages on down */ for( i = &ip->r_msgs; i <= &ip->r_hiwat; *i++ = 0 ); /* see if we can get an entry in the contab */ if( (ip = entcontab( hl,ip )) == 0 ) log_to_ncp( "wf_setup: no connection entries"); wf_inc_alloc(); wf_update_skt( ip ); return( 0 ); } /*name: wf_frlse function: to release a network file if everyone is finished with it algorithm: call net_frlse return 0 parameters: none returns: zero globals: ncprs.id calls: net_frlse (its in nopcls.c) called by: ncpwrite thru ncpoptab (opcode # 6) history: initial coding 7/7/76 by S. F. Holmgren */ wf_frlse() { /* see if the file in question can be released */ net_frlse( ncprs.id ); return( 0 ); } /*name: wf_stimo function: to request an interrupt after a given time has elapsed algorithm: call timeout return 0 parameters: none returns: zero globals: &daetim calls: timeout (sys) called by: ncpwrite thru ncpoptab (opcode # 7) history: initial coding by greep */ wf_stimo() { int hz; int daetim(); /* see if the file in question can be released */ hz.lobyte = cpass(); hz.hibyte = cpass(); timeout(&daetim,0,hz*60); /* set up a callout */ return( 0 ); } /*name: wf_update_skt function: save info concerning local and foreign sockets algorithm: copy down local socket copy down foreign socket parameters: address of a connection table entry returns: nothing globals: none calls: cpass called by: wf_setup wf_mod history: initial coding 4/16/76 by S. F. Holmgren */ wf_update_skt( con ) char *con; { register char *conp; register int i; conp = &(con->c_localskt); i = 6; do *conp++ = cpass(); while( --i ); } /*name: daetim function: to send a message to the daemon indicating a timeout has elapsed algorithm: set a flag for ncpread wake up daemon if waiting note: this does not put a message into the ncp read queue because it is running at priority 6 (from the clock interrupt) so it could interrupt an IMP interrupt routine parameters: none returns: nothing globals: ncptimo calls: wakeup called by: clock(sys) through callout set up by wf_stimo history: initial coding by greep */ daetim() { ncptimo++; wakeup( &ncprq ); }