# #include "../h/param.h" #include "../h/netparam.h" #include "../h/user.h" #include "../h/buf.h" #include "../h/net.h" #include "../h/netbuf.h" #include "../h/imp.h" #include "../h/imp11a.h" #include "../h/hosthost.h" #include "../h/proc.h" #include "../h/file.h" #include "../h/ncp.h" #include "../h/contab.h" #ifdef NETWORK /* jsq bbn 10/19/78 */ extern int localnet; #ifdef IMPPRTDEBUG int impdebug 0; #endif IMPPRTDEBUG /* JC McMillan */ /* SCCS PROGRAM IDENTIFICATION STRING */ /*char id_impio[] "~|^`impio.c\tV3.9E1\t25Jan78\n";*/ /* this array is indexed by the above op codes to give the length of the command */ #ifdef NCP /* jsq bbn 10/19/78 */ 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 */ }; #endif NCP /*name: impopen function: imp input process algorithm: fork a kernel process to handle input from net child: close parents files loop: init imp interface on first pass thru loop and send the noops read header if no error, call parse routine, which will read in rest of message else restart interface go to loop parameters: none returns: nothing globals: ncpopnstate calls: imp_init sleep(sys) newproc(sys) implread (imp.h) imp_input imp_reset impopen impstrat spl_imp called by: ncpopen (ncpclose awakens this code) (imp_iint awakens this code) history: initial coding 1/7/75 by S. F. Holmgren modified 10/5/75 chopped initialize into imp_init and started checking imp_error bit and inited if bit was on S. F. Holmgren modified 04 Jan 77 for ACC LH-11 by JSK modifed 25Jan78 to keep smalldaemon from returning at bottom added line to clear flags in NOP buffer before each use. jsq bbn101978 fixed nop length jsq BBN 3-20-79 */ impopen() { register int *fp, *p; int needinit, inx; /* * shouldn't we check to see that we don't get in here twice ? */ if (newproc()) { /* fork input process */ /* release any hold we may have on parents files */ for( fp = &u.u_ofile[0]; fp < &u.u_ofile[NOFILE]; fp++ ) if( (p = *fp) != NULL ){ p->f_count--; *fp = 0; } needinit = 1; /* flag to force initialization */ for (;;) /* body of input process */ { spl_imp(); if (needinit) { needinit = 0; imp_init (); for ( inx = 0; inx < 3; inx++ ) { /* send 3 noops */ #ifndef SHORT /* tell imp we want long leaders */ oimp.o_nff = NFF; /* always zero */ oimp.o_dnet = 0; /* nothing here this time */ oimp.o_lflgs = 0; /* */ oimp.o_htype = 0; /* */ oimp.o_host = 0; /* */ oimp.o_imp = 0; /* */ oimp.o_link = 0; /* no padding after the i-h leader */ oimp.o_subtype = 0; /* no message length in this one */ oimp.o_mlength = 0; #endif SHORT /* set opcode to h_i_nop */ oimp.o_type = ih_nop; #ifndef BUFMOD /* especially not BUSY */ impobuf.b_flags = 0; /* set addr for output */ impobuf.b_addr = &oimp; /* send the imp leader bytes */ impobuf.b_wcount = impllen; /* send one */ impstrat( &impobuf ); iowait( &impobuf ); /* wait for one to fin */ #endif BUFMOD #ifdef BUFMOD sndnetbytes(&oimp,impllen,0,0,1); #endif } /* set parameters on input leader */ #ifdef NCP imp.nrcv = ncp_rcv; /* perm receive comm here */ #endif NCP printf("\nIMP:Init\n"); /*JCM*/ implread(); /* set up input side of imp interface */ } sleep( &imp,-25 ); /* wait for something */ if( ncpopnstate == 0 ) break; /* we down? */ if (imp_stat.error) { printf ("\nIMP: input error, resetting\n"); imp_reset (); needinit++; }else{ imp_input(); /* handle it */ } } imp_dwn(); /* clean up kernel data */ exit (); /* imp input process never returns */ } } /*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 impi_adr == &imp.type 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 until the endmsg flag is raised. There are three orthogonal conditional compilation flags - NCP - Include code for distributing to the ncpkernel This affects the most code. RMI - Distribute to the rawkernel This puts in hooks to catch things before the ncp gets them. SHORT - Use short leaders (or long ones if not defined) This affects only the length and address of the leader buffer and the way the host number is gotten from the leader. There are three daemon states - ncpopnstate == 0 - No daemon up; this should never occur here. ncpopnstate == 1 - ncpdaemon up; either rmi or ncp can claim messages (also depending on compilation flags). ncpopnstate == -1 - only the rmi can claim messages. if buffering data if this message is raw, or no ncp, or rawdaemon up, rawhh handles the buffering else call hh let him handle it in either case, return; there's nothing more to do. ....we are reading a leader.... get host number from leader according to leader style if endmsg, means imp to host msg received call ih and let him deal with that type (there is code in ih to catch ones for rmi) else if there is rmi and this is a raw message buffer the leader and start reading the rest of it else if there is rmi and no ncp or if the rawdaemon is up flush the message, there's no place else for it to go. return ....the rest of the routine is only used by the ncp.... 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: struct imp (imp.h) struct for accessing various imp leader fields implilob (imp.h) pointer to the beginning of imp struct impi_host (imp.h) put host number from leader here impi_sockt (imp.h) set to addr of user inode impi_con (imp.h) addr of rawentry imp_stat.inpendmsg to see if the end of the message was read ncpopnstate(netparam.h) to see if rawdaemon is up 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 map host link number in conn tab to sktp ptr printf prt_dbg prints debugging msg on terminal swab (sys) rawhh (rawnet.c) rawhostmsg (rawnet.c) rawlget (rawnet.c) stolhost (btest.c) called by: imp_open history: initial coding 1/7/75 by Steve Holmgren Modified by J.C.McMillan for LH-DH-11 Jan77 Modified for modularity 04Jan77 JSK Suppressed Link # ? message 5Jun77 J.S.Kravitz 26Sep78 added calls on rawhh, rawhostmsg, rawlget jsq bbn 3-?-79 long hosts jsq BBN 3-21-79 RMI input is demultiplexed on connection (impi_con) rather than socket (impi_sockt) jsq BBN 3-21-79 comments and code straightened somewhat jsq BBN 3-21-79 */ imp_input() /* imp input handler */ { register char *c; /* does unsigned arith & general logic*/ register char *errtext; /* pts to 1 of several texts for errmsg */ #ifndef BUFMOD if (impi_adr != implilob) { /*...if the leader is not being read... */ /* data is being buffered */ #endif BUFMOD #ifdef BUFMOD if ( (impi_adr != ( (implilob >> 6) & 01777 ) ) /*...if the leader is not being read... */ || (impi_offset != (implilob & 077)) ) { #endif BUFMOD #ifdef RMI #ifdef NCP /* want everything if rawkernel open or no ncp */ if ((impi_msg && (impi_msg -> b_resv & b_raw)) || (ncpopnstate < 0)) #endif NCP { rawhh(); /* rawmessage */ return; } #endif RMI #ifdef NCP hh(); /* regular */ #endif NCP return; } /*...an 8 byte leader-read is being processed*/ /*get host from leader now so we don't have to every time we want it*/ #ifndef SHORT impi_host = 0; impi_host.h_imp0 = imp.imp.hibyte; impi_host.h_imp1 = imp.imp.lobyte; /* swap imp field */ impi_host.h_hoi = imp.host; /* use host directly */ if (impi_host) impi_host.h_net = localnet; #endif SHORT #ifdef SHORT impi_host = stolhost(imp.host); /* convert */ #endif SHORT if (imp_stat.inpendmsg) { ih(); /* if 'endmsg', a 4 byte IH leader is assumed */ return; } #ifdef RMI if (impi_con = rawhostmsg ()) { /* maybe is a raw message */ rawlget(); return; } #ifdef NCP if (ncpopnstate < 0) /* if rawkernel open or no ncp, flush */ #endif NCP { printf("imp: leader?\n"); flushimp(); return; } #endif RMI #ifdef NCP /* the rest of the routine is only used by the ncp */ if (imp.pad1 != 0 || (imp.type =& 0137)) /* if illegal leader */ { errtext = "Pad or type error"; /* JC McMillan */ iherr: impi_sockt = 0; imp_stat.i_leaderr++; if (errtext) printf("\nIMP:%s\n", errtext); # ifdef IMPPRTDEBUG prt_dbg(" ", 2*(impi_wcnt+imp_stat.inpwcnt), -1, &imp.type); # endif IMPPRTDEBUG /* JC McMillan */ flushimp(); } else /* Pad valid on HH leader */ if (imp.link == 0) /* if a HH protocol (link==0) */ { if (imp.bsize!=8 || (c=swab(imp.bcnt))>120) { errtext = "HH Ldr format"; /* JC McMillan */ goto iherr; } impi_sockt = 0; nxtbuf: # ifdef IMPPRTDEBUG prt_dbg("HHl", 2*(impi_wcnt+imp_stat.inpwcnt), 3, &imp.type); /* print 8 bytes of leader*/ # endif IMPPRTDEBUG /* JC McMillan */ ihbget(); } else /*... must be HH data msg, and link must be validated */ if( impi_sockt = imphostlink( imp.link & 0177 )) goto nxtbuf; /* got iptr cont reading */ else /*All else has failed! Assume HH data msg w/ invalid link*/ { errtext = 0; /* JSK 5Jun77 */ /* errtext = "Link#?"; */ goto iherr; /* whos he err */ } #endif NCP } /*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: impi_msg->b_len= impi_flush= sktp->r_flags= sktp->r_bytes= sktp->r_msgs= sktp->r_msgq sktp->r_qtotal= imp.nrcv calls: freemsg to destroy buffer data wakeup (sys) to allow user to run rmovepad to remove imp padding and set length to_ncp to pass data to ncpdaemon hh1 for further decoding and switching of data implread (imp.h) to start another leader read flushimp to continue flushing data from imp ihbget continue bufferin data prt_dbg prints debugging msg on terminal emerbuf debug output of flushed data catmsg assemble incoming message called by: imp_input history: initial coding 1/7/75 by Steve Holmgren check for something in impi_msg 8/16/76 S. Holmgren Modified Jan77 for LH-DH-11 by JSK& JC McMillan server telnet test stuff deleted 12Jun77 JSKravitz lines added for network file await/capacity 7/31/78 S.Y. Chiu changed for long or short leaders by jsq bbn 12-6-78 */ #ifdef NCP hh() { register struct rdskt *sktp; register char *src; register char *dest; struct netbuf *bufp; int cnt; #ifndef MSG int *sitp; /* sitp used exclusively by await/capac */ #endif MSG char *ii; int ll; #ifdef BUFMOD int dummy; #endif sktp = impi_sockt; if( impi_msg ) /* if there is anything in the msg */ impi_msg->b_len = net_b_size; /* The above sets a maximum bound on the number of ** characters in the buffer... rmovepad will ** more accurately set this length. */ if (imp_stat.inpendmsg) { if( impi_flush ) /* finished flushing */ { # ifdef IMPPRTDEBUG prt_dbg(" ^", net_b_size+2*imp_stat.inpwcnt, -1, emerbuf()); # endif IMPPRTDEBUG /* JC McMillan */ freemsg( impi_msg ); /* destroy any bfred data */ impi_msg = 0; /* get rid of previous msg */ impi_flush = 0; /* reset flushing */ if (sktp) /* was user proc involved */ { sktp->r_flags =| n_eof; /* set err */ wakeup( sktp ); } } else { /* destroy the first data byte, its part of the leader */ #ifndef BUFMOD bufp = impi_msg->b_qlink; bufp->b_len--; src = dest = &bufp->b_data[0]; src++; cnt = net_b_size+1; while( --cnt ) *dest++ = *src++; #endif BUFMOD #ifdef BUFMOD bytesout(&impi_msg,&dummy,1,1); #endif BUFMOD rmovepad(); /* remove padding and set length */ if (sktp) /* if (sktp!=0) then its a user-lvl msg*/ { # ifdef IMPPRTDEBUG prt_dbg("Usr<", (src=bufp->b_len) > 15 ? 15:src, 1, &bufp->b_data[0]); # endif IMPPRTDEBUG /* JC McMillan */ if( sktp->r_flags&n_toncp) /* data to ncp? */ to_ncp(&imp.nrcv,toncpll,impi_msg); else /* no give to user and wakeup */ { /* dec msgs allocated */ sktp->r_msgs--; sktp->r_msgq = catmsg( sktp->r_msgq,impi_msg ); sktp->r_qtotal =+ impi_mlen; wakeup( sktp ); /* there might be an await * on this read socket, so call awake */ #ifndef MSG sitp = sktp; if (sitp = *(--sitp)) awake(sitp,0); #endif MSG #ifdef MSG if (sktp->itab_p) awake(sktp->itab_p, 0); #endif MSG } } else /* nope hh msg */ { hh1(); /* let him handle this */ } } impi_msg = 0; implread(); /* start another leader read */ } else if( imp_stat.inpwcnt == 0 ) /* filled our buffer? JSK */ { /* not end msg - keep flushing or reading */ if( impi_flush ) /* flushing? */ { # ifdef IMPPRTDEBUG prt_dbg(" +", net_b_size, -1, emerbuf()); # endif IMPPRTDEBUG /* JC McMillan */ flushimp(); /* yes - keep flushing */ } else ihbget(); /* no cont reading data */ } else printf("\nIMP:Phantom Intrp(Csri=%o)\n", imp_stat.inpstat); } #endif NCP /*name: ih function: To look at all imp to host messages and handle rfnms, incomplete transmissions, and nops algorithm: if rawih completely processes it as a rawmessage leader, return 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 imp.nrcv calls: siguser to let user see rfnms, incomptrans or err data to_ncp to ship leaders to ncpdaemon implread (imp.h) to start another leader read prt_dbg prints debugging msg on terminal called by: imp_input history: initial coding 1/7/75 by Steve Holmgren 26Sep78 added call on rawih jsq bbn 12-6-78 changed for short or long leaders jsq bbn pick up local host from nop jsq bbn 2-9-79 */ ih() /* handles all imp to host messages */ { register char *p; # ifdef IMPPRTDEBUG prt_dbg("IH ", 8+2*imp_stat.inpwcnt, 3, &imp.type); /* print 'N' bytes of leader (us.==4)*/ # endif IMPPRTDEBUG /* JC McMillan */ if ((imp.type & 0137) == ih_nop) { netparam.net_lhost = impi_host; } #ifdef RMI if (rawih()) return; #endif RMI #ifdef NCP switch( imp.type =& 0137 ) { case ih_rfnm: siguser( n_rfnmwt ); /* tell user rfnm arrived */ case 15: /* ignore new style header */ case ih_nop: break; /* ignore nops */ case ih_edata: case ih_ictrans:siguser( n_xmterr ); /* tell user about his problem */ default: to_ncp( &imp.nrcv,toncpll,0 );/* send leader to ncp */ } #endif NCP impi_msg = 0; implread(); /* 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 allow user to run 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 imp.nrcv 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 siguser biton reset_host 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 changed to_ncp arg 12-6-78 jsq bbn */ #ifdef NCP siguser( sigflg ) /* called when user needs waking up. the passed flag is ored into his flag field and he is awakened */ { register conentry; if( imp.link && (conentry = imphostlink( imp.link | 0200 )) ) { if( conentry->w_flags & n_toncp ) to_ncp( &imp.nrcv,toncpll,0);/* give to ncp */ else { conentry->w_flags =| sigflg; /* set flags */ wakeup( conentry ); } } else { /* user waiting for control link rfnm? */ if( host_on( host_map,impi_host ) != 0 ) { /* say rfnm here */ reset_host( host_map,impi_host ); /* let any users battle it out */ host_wakeup( host_map, impi_host ); } else /* no users waiting ship to daemon */ to_ncp( &imp.nrcv,toncpll,0 ); } } #endif NCP /*name: prt_dbg function: To print debugging data in a consistent manner. parameters: str -- A string of length <= 3, used as first text on line. cnt -- The count of the number of bytes to print. typ -- The extended interpretation type: 1 - general data 2 - HH protocol data 3 - imp leader data Negative # indicates MANDATORY printf, regardless of impdebug flag adr -- The address from which to start printing bytes. returns: nothing globals: impdebug iff, print debugging information calls: printf called by: ih hh imp_output prt_odbg imp_input history: Coded 1/12/76 by JC McMillan to facilitate testing ACC imp-interface */ #ifdef IMPPRTDEBUG char *prt_ops [] {"nop","rts","str","cls","all","gvb","ret","inr" ,"ins","eco","erp","err","rst","rrp","???" }; char *prt_types[] { "Reglr","ErLdr","GoDwn","UnCtl","No-Op","RfNM ","DHost","D Imp" ,"ErDat","IncMs","Reset","RefTA","RefWt","RefST","Ready","?"}; prt_dbg(str, cnt, typ, adr) char *str, *adr; int cnt,typ; { register int count, bytex, newlin; char *address; /* holds init value of adr */ if (typ < 0) /* if typ<0, msg MUST be printed */ { typ = -typ; printf("\nIMP "); } else { /* handle optional msgs */ if (!impdebug) return; printf("\n"); } printf("%s:", str); if (!cnt) goto prtcrlf; if (cnt<0) cnt=512; cnt++; newlin = count = 0; address = adr; while (--cnt) { bytex = *adr & 0377; printf(" %o", bytex); if (typ==2 && !count--) { printf("=%s" ,prt_ops [ bytex = (bytex>=0 && bytex<14 ) ? bytex:14] ); count = (bytex==14 ? -1 : hhsize[bytex]-1); } if (((newlin++ & 017)==017) && (cnt!=1)) printf("\n +"); adr++; } if (typ == 3) printf("<%s", prt_types [*address&017] ); prtcrlf: printf("\n"); } #endif IMPPRTDEBUG /*name: flushimp function: increment number of imp flushes and reload imp interface with buffer to dump data into algorithm: set impi_flush flag handle statistics reload imp interface with black hole parameters: none returns: nothing globals: impi_flush= imp_stat.i_flushes= calls: emerbuf to get address of black hole impread to load imp interface with address of hole called by: imp_input ihbget hh history: initial coding 1/7/75 by Steve Holmgren Modified jan/77 by JC McMillan to imbed debug-aid for ACC intrfc */ flushimp() { /* repeatedly called when we want imp interface cleaned out */ #ifdef BUFMOD register char *temp; #endif BUFMOD impi_flush = 1; imp_stat.i_flushes++; #ifndef BUFMOD impread( emerbuf(),net_b_size ); #endif BUFMOD #ifdef BUFMOD temp = emerbuf(); impread( ( (temp >> 6) & 01777 ), ( temp & 077 ), net_b_size); #endif BUFMOD } /*name: ihbget function: To reload the imp interface with a buffer to store data into algorithm: If a buffer is available set impi_msg to address call impread to reload imp interface registers else couldnt get a buffer start flushing data parameters: none returns: nothing globals: impi_msg= calls: appendb to add another buffer to impi_msg impread to load imp interface registers flushimp to flush imp data if couldnt get buffer printf (sys) called by: imp_input hh history: initial coding 1/7/75 by Steve Holmgren */ ihbget() /* stands for imp host buffer getter */ { register struct netbuf *bp; /* called when there is data to buffer from the imp */ /* appendb returns 0 if cant get buffer */ if( bp=appendb( impi_msg ) ) { impi_msg = bp; #ifndef BUFMOD impread( bp->b_data, net_b_size); #endif BUFMOD #ifdef BUFMOD impread( bp->b_loc, 0, net_b_size); #endif BUFMOD } else { printf("\nIMP:Flush(No Bfrs)\n"); flushimp(); } } /*name: hh1 function: To search through host to host protocol messages strip out any that apply to the user ( allocates for now ) algorithm: Looks through each buffer of the message on host to host protocol boundaries for and allocate protocol msg. When one is found, copies the msg into hhmsg and overwrites with host to host nops. Calls allocate with the allocate protocol command with deals with it at the user level. once all the msg has been passed through, it as well as the imp to host leader is passed to the ncpdaemon for further processing. parameters: none returns: nothing globals: impi_msg impi_mlen hhsize[] imp.nrcv calls: allocate to deal with allocate commands rcvd from net to_ncp to send uninteresting protocol to ncpdaemon prt_dbg to note all flush calls if in debug mode bytesout catmsg imphostlink vectomsg called by: hh history: initial coding 1/7/75 by Steve Holmgren modified 1/1/77 by Steve Holmgren to simplify and correct bug related to hh protocal crossing buffer boundary changed to_ncp arg jsq bbn 12-6-78 */ #ifdef NCP hh1() { register int hhcom; register char *sktp; register cnt; static char *daemsg, hhproto [96]; daemsg = 0; while( impi_mlen > 0 ) { /* while things in msg */ #ifndef BUFMOD hhcom = (impi_msg->b_qlink)->b_data[0] & 0377; #endif BUFMOD #ifdef BUFMOD hhcom = fbbyte(impi_msg->b_qlink->b_loc, 0); #endif BUFMOD if( hhcom > NUMHHOPS ) { daemsg = catmsg( daemsg,impi_msg ); goto fordaemon; } cnt = hhsize[ hhcom ]; /* get bytes in this command */ impi_mlen =- cnt; /* decrement impi_mlen */ if( bytesout( &impi_msg,&hhproto,cnt,1 )) /* msg not long enough */ impi_mlen = 0; /* force msg empty */ else if( hhcom == hhall && (sktp=imphostlink( hhproto[1]|0200 )) ) { allocate( sktp,&hhproto ); continue; } else if( hhcom == hhins && (sktp=imphostlink( hhproto[1]&0177 )) ) { if( (sktp->r_rdproc) && ((sktp -> r_rdproc) -> p_stat) ) { /* there ? */ #ifdef MSG sktp->INS_cnt =+ 1; /* increment count */ if (sktp->itab_p) awake(sktp->itab_p, 0); /* awake awaiting process */ #endif MSG psignal( sktp->r_rdproc,SIGINR ); } continue; } else if( hhcom == hhinr && (sktp=imphostlink( hhproto[1]|0200 )) ) { if( (sktp->r_rdproc) && ((sktp -> r_rdproc) -> p_stat) ) { #ifdef MSG sktp->INR_cnt =+ 1; /* increment count */ if (sktp->itab_p) awake(sktp->itab_p, 0); /* awake awaiting process */ #endif MSG psignal (sktp -> w_wrtproc, SIGINR); } continue; } else if( hhcom == hhnop ) continue; vectomsg( &hhproto,cnt,&daemsg,1 ); /* got here then give it to daemon */ } if( daemsg != 0 ) /* something in msg */ fordaemon: to_ncp (&imp.nrcv, toncpll, daemsg); /* send to daemon */ } #endif NCP /*name: allocate function: To look over host to host allocate protocol messages . determine whether they are going to ncpdaemon or user send off to ncpdaemon, inc appropriate user fields. algorithm: if host_link in conn tab if socket flags say to ncpdaemon send to ncpdaemon with imp to host leader else update num of messages alocated update number of bits allocated tell user allocate came in let user run parameters: allocp pointer to a host host allocate returns: nothing globals: imp.nrcv sktp->w_msgs= sktp->w_falloc= sktp->w_flags= calls: vectomsg to build a msg from vec passed to send to ncp daemon to_ncp to ship the allocate off to the ncp daemon dpadd (sys) to add two double precision words wakeup (sys) to let the user run called by: hh1 history: initial coding 1/7/75 by Steve Holmgren modified to awake "awaiting" processes 8/14/78 S.Y. Chiu changed to_ncp arg jsq bbn 12-6-78 */ #ifdef NCP allocate( skt_ptr,allocp ) struct wrtskt *skt_ptr; { /* called from hh1 when a hh allocate is received */ register char *ap; register struct wrtskt *sktp; struct netbuf *msgp; #ifndef MSG int *sitp; #endif MSG sktp = skt_ptr; ap = allocp; msgp = 0; if (sktp->w_flags & n_toncp) { vectomsg( allocp,8,&msgp,1 ); to_ncp( &imp.nrcv,toncpll,msgp ); } else { sktp->w_msgs =+ swab( ap->a_msgs ); sktp->w_falloc[0] =+ swab(ap->a_bitshi); dpadd(sktp->w_falloc,swab(ap->a_bitslo)); sktp->w_flags =| n_allocwt; wakeup( sktp ); /* wake up "await" processes, if any */ #ifndef MSG sitp = sktp; if (sitp = *(--sitp)) awake(sitp,0); #endif MSG #ifdef MSG if (sktp->itab_p) awake(sktp->itab_p, 0); #endif MSG } } #endif NCP /*name: rmovepad function: To remove the padding attached to every host host protocol msg and standard message by the imp algorithm: given a bytesize in number of bytes in that size, calculate the number of 8 bit bytes. set the message length to that size run through the message a buffer at a time subtracting the buffer length from the calculated size. eventually it will go negative, since the number of bytes calculated is less that the actual number of bytes in the msg subtract the number of pad bytes from the last buffer in the message to setthe number of actual number of data bytes then free any remaining buffers. set impi_msg to the new last buffer. parameters: none returns: nothing globals: impi_mlen= impi_msg= impi_msg->b_qlink calls: swab (sys) to switch top and bottom bytes freebuf to release the last buffer from the message called by: hh history: initial coding 1/7/75 by Steve Holmgren added bytesizes multiple of 8 01/27/78 S. F. Holmgren modified so that impi_mlen is correctly set 8/11/78 S.Y. Chiu */ #ifdef NCP rmovepad() { /* calculates number of bytes from impleader then runs through impsg buffers adding up counts until number calculated or end of msg is reached. sets impcnt tothe min of amt in msg and calculated and discards any excess bytes */ register struct netbuf *bfrp; register cnt; impi_mlen = swab( imp.bcnt ); /* get # bytesize bytes */ impi_mlen = cnt = (impi_mlen * imp.bsize)/8; /* turn into 8-bit bytes */ impi_msg = bfrp = impi_msg->b_qlink; /* pt at first bfr in msg */ while(((cnt =- (bfrp->b_len & 0377)) > 0 ) /*get to last bfr with valid data */ && (bfrp->b_qlink != impi_msg)) /* protect against wrapping around -- JC McMillan */ bfrp = bfrp->b_qlink; if (cnt>0) /* jcm -- note errors */ { printf(" \nIMP:Missing %d B\n", cnt); impi_mlen =- (( cnt*8 ) / impi_sockt->r_bsize ); } if (cnt < 0) /* cnt has -(# bytes to discard) */ bfrp->b_len = (bfrp->b_len & 0377) + cnt; /* discard extra bytes this buffer */ while( bfrp->b_qlink != impi_msg ) /* while not pting at 1st bfr */ freebuf(bfrp); impi_msg = bfrp; /* set new handle on msg */ } #endif NCP /*name: imphostlink function: Checks to see if the current host and link are in the connection table (conn tab). Checks to see if the socket is open, if so returns a pointer to the socket. If not in conn tab or socket not open returns zero algorithm: if host link in conn tab if skt open return socket ptr return zero parameters: link link to be checked with current host returns: zero if not in conn tab or socket not open socket ptr if in conn tab and socket open globals: imp.host sktp->r_flags calls: incontab to see if host link is in conn tab called by: hh1 imp_input siguser history: initial coding 1/7/75 by Steve Holmgren */ #ifdef NCP imphostlink( link ) char link; { register sktp; if( sktp = incontab( impi_host, (link & 0377), 0 )) { sktp = sktp->c_siptr; /* contab returns ptr to entry must get skt pointer */ return( sktp ); } return( 0 ); } #endif NCP /*name: imp_dwn function: clean up ncp data structures so that an ncpdaemon restart will work correctly. algorithm: reset the imp interface free any input message clean up input variables clear out all messages queued for the output side reset any rfnm bits let the kernel buffer code clean up its own parameters: none returns: nothing globals: impi_msg = impi_mlen = impi_sockt = impi_con impi_flush = impotab (forward and backward links) host_map[-] = calls: freemsg ncp_bfrdwn imp_reset printf host_clean called by: imp_open history: initial coding 6/22/76 by S. F. Holmgren modified 4/1/77, S.M. Abraham to fix bug in loop that frees all msgs in output queue. It wasn't resetting the msg ptr to the next msg in the queue. printf changed to 'NCP' from 'IMP' 31AUG77 JSK long host mods jsq bbn 1-30-79 clear impi_con jsq BBN 3-21-79 */ imp_dwn() { register char *p; register int *q; /* reset the imp interface */ imp_reset(); /* JSK */ /* cleanup the input side */ freemsg( impi_msg ); impi_msg = impi_mlen = impi_sockt = impi_con = impi_flush = 0; /* clean up the output side */ impotab.d_active = 0; /* get rid of messages waiting to be output */ #ifndef BUFMOD p = impotab.d_actf; while (p) { if( p->b_flags & B_SPEC ) /* this a net message */ freemsg( p->b_dev ); /* free it */ else iodone( p ); /* sys buffer say done */ p = p -> b_forw; /* pt to next msg */ } #endif BUFMOD #ifdef BUFMOD freemsg(impotab.d_actf); #endif BUFMOD impotab.d_actf = impotab.d_actl = 0; #ifdef NCP /* clear out any waiting rfnm bits */ host_clean(&host_map); #endif NCP printf("\nNCP:Down!\n"); /*JCM & JSK*/ /* let the net message software clean up */ ncp_bfrdwn(); } /*name: impstrat function: Used to link output buffers into the imp output queue for transmission to the network. algorithm: if queue empty put buffer at front. else link buffer to end if imp output is not active start it up parameters: abp - pointer to the buffer to be sent returns: nothing globals: impotab.d_actf= impotab.d_actl= bp->b_forw= calls: imp_output prt_odbg prints debugging msg on terminal spl_imp called by: sndnetbytes (kerbuf.c) impopen history: initial coding 1/7/75 by S. F. Holmgren Modified 05Jan77 for LH-DH-11 by JSK */ #ifndef BUFMOD impstrat( abp ) struct buf *abp; { register struct buf *bp; bp = abp; bp->b_forw = 0; /* null forward pointer this buffer */ spl_imp(); if( impotab.d_actf == 0 ) /* anything in list ?? */ impotab.d_actf = bp; /* no make this the first */ else impotab.d_actl->b_forw = bp; /* make this new last */ /* set last to this */ impotab.d_actl = bp; if (impotab.d_active == 0) /* do we need to start the imp? */ { imp_output(); /* yep kick it over */ # ifdef IMPPRTDEBUG prt_odbg(); /* if impdebug set, scan & print leader */ # endif IMPPRTDEBUG /* JC McMillan */ } } #endif BUFMOD #ifdef BUFMOD impstrat( abp ) struct netbuf *abp; { register struct netbuf *bp; bp = abp; spl_imp(); if (impotab.d_actf == 0) impotab.d_actf = bp->b_qlink; msg_q(&impotab.d_actl, 0, 0, bp); if (impotab.d_active == 0) imp_output(); } #endif /*name: prt_odbg function: aid in debugging output stream to imp algorithm: interprete data in a minor way, then use prt_dbg to print. parameters: none -- uses same presumptions regarding globals as does imp_output returns: nothing globals: impotab.d_actf impdebug calls: prt_dbg prints debugging msg on terminal called by: impstrat imp_oint history: coded jan 77 by JCM */ #ifdef IMPPRTDEBUG int impodebug 0; prt_odbg() { register struct buf *bp; register char *cnt; register char *ldr; extern impdebug; if ((!impdebug) || (impodebug)) return; if((bp = impotab.d_actf) == 0) return; /* return nothing to do */ ldr = bp->b_addr; cnt = bp->b_wcount; prt_dbg(cnt<5 ? " HI":"<HH", cnt>9 ? 9:cnt, 3, ldr); if ((cnt>9) & (ldr->o_link==0)) prt_dbg("pHH", cnt-9>128? 128:cnt-9, 2, ldr+9); } #endif IMPPRTDEBUG /* JC McMillan */ /*name: imp_odone function: Check conditions of last output transfer and start next output to interface algorithm: Get the first buffer from the output queue If there was an error in output, it is indicated, and the buffer returned. If the buffer embodies a network message( B_SPEC ) and the last buffer of that message has not been sent, Get to next buffer in net message Update w_count for that buffer Update next buffer pointer(av_forw) so next time come through things will be easier. Decide whether to set endmsg bit on not. Start up output side otherwise get next buffer in output queue if this was a net message give it back to the system otherwise say that the system buffer( buf.h ) is done if there is nothing to do clean up a little otherwise start up the output side again. parameters: none returns: nothing globals: impotab.d_active buffer->b_flags= buffer->b_error= buffer->b_addr= buffer->b_wcount= buffer->av_forw= buffer->b_blkno= impotab->d_actf= calls: imp_output freemsg iodone called by: imp output interrupt routine history: initial coding 1/7/75 by S. F. Holmgren recoded for modularity 15Feb77 JSK */ #ifndef BUFMOD imp_odone (errbits) char errbits; { register char *buffer; register struct devtab *iot; register char *msg; iot = &impotab; buffer = iot->d_actf; /* pt at first buffer in list */ if( errbits ) /* timeout errror */ { buffer->b_flags =| B_ERROR; buffer->b_error = errbits; } else /* if kernel msg and has multi buffers send next buffer */ if(( buffer->b_flags & B_SPEC ) && /* this last bfr in msg */ (buffer->b_blkno & 01)) { /* no we disabled endmsg last time must send some more */ msg = buffer->av_forw; /* set next buffer address into header */ buffer->b_addr = msg->b_data; /* set length of that buffer into length field */ buffer->b_wcount = ( msg->b_len & 0377 ); /* if this is not the last buffer then disable endmsg */ buffer->b_blkno = (msg == buffer->b_dev) ? 0 : 1; /* update next msg buffer field */ buffer->av_forw = msg = msg->b_qlink; /* send to imp */ imp_output(); return; } iot->d_actf = buffer->b_forw; /* set top to next */ /* give msg back -- ptr put in by sndnetbytes */ if( buffer->b_flags&B_SPEC ) freemsg( buffer->b_dev ); else iodone( buffer ); /* say done with buffer */ if( iot->d_actf == 0 ) /* done for awhile?? */ { iot->d_actl = 0; /* remove queue links */ iot->d_active = 0; /* say we are done */ } else { imp_output(); /* do some more */ # ifdef IMPPRTDEBUG prt_odbg(); /* if impdebug set, scan & print leader */ # endif IMPPRTDEBUG /* JC McMillan */ } } #endif #ifdef BUFMOD imp_odone (errbits) char errbits; { register char *nbp; register struct devtab *iot; register char *msg; /* free UNIBUS map */ mapfree(&i11a_obuf); iot = &impotab; nbp = iot->d_actf; iot->d_actl = freebuf(iot->d_actl); if (iot->d_actl == 0) iot->d_actf = iot->d_active = 0; else { iot->d_actf = ( (iot->d_actl) -> b_qlink ); imp_output(); } } #endif BUFMOD #endif NETWORK