# #include "../h/param.h" #include "../h/netparam.h" #include "../h/user.h" #include "../h/file.h" #include "../h/inode.h" #include "../h/reg.h" #include "../h/buf.h" #include "../h/net.h" #include "../h/netbuf.h" #include "../h/imp.h" #include "../h/rawnet.h" #ifdef RMI extern int localnet; long ZERO0L 0; /* fake a long constant zero */ /* * system call routines: * rawopen, rawclose, rawread, rawwrite * * used by the above: * rawrel, rawinode, rawrw * * imp input interrupt routines: * rawlget, rawhh, rawhostmsg, rawih, rawstrat * */ /* name: rawopen function: to implement the open system call on /dev/net/rawmsg algorithm: if the file being opened is not /dev/net/rawmsg if rawkernel is open give error to keep netopen from working release inode, and return -1 return 0 give /dev/net/rawmsg inode back to system error if ncp is not up (because it initializes imp, buffers, etc.) get user's parameters give error if they aren't legal try to get a file structure clear read and write rawskt pointers if can't get a rawfiletab entry, return with ERAWTAB say file is netfile, open, given mode try to get inodes for read or write socket as specified by user and put entries in rawtab on error, release inodes (rawrel) and file structure and clear file descriptor entry return pointer to file structure parameters: aip - inode of file being opened mode - pointer to open parameters in user space returns: zero - not /dev/net/rawmsg (let netopen do its stuff) pointer to file structure - for communication over specified msg -1 - error globals: ncpopnstate 1: ncpkernel open; -1: rawkernel open; 0: neither LOMSG - lowest message parameter allowed calls: bcopyin falloc (sys) rawinode (rawmain.c) spl_imp (sys) spl0 (sys) getrawtab (rawtable.c) putrawtab (rawtable.c) rawrel (rawmain.c) called by: netopen (nopcls.c) history: initial coding jsq bbn Fri Sep 22 1978 changed to convert host to long form jsq bbn 12-6-78 also for variable LOMSG use FRAW flag in file structure jsq BBN 3-14-79 release file here rather than in rawrel on failure jsq BBN 3-14-79 unused open options removed jsq BBN 3-21-79 */ rawopen (aip, amode) struct inode *aip; #ifndef BUFMOD int *amode; /* bcopyin is used just in case this is odd */ #endif BUFMOD #ifdef BUFMOD char *amode; #endif BUFMOD { register *sktp; register struct netfile *fp; register i; #ifdef BUFMOD char *cp; #endif BUFMOD int mode; long host; int low, high; struct rawparams ropen; sktp = aip; if (!sktp || (sktp -> i_addr[0] != RAWDEV)) { /* netopen uses 0 aip */ #ifdef NCP if (ncpopnstate < 0) { /* keep netopen from making a fool */ u.u_error = ENCPNO; /* of itself when rawkernel */ if (sktp) iput (sktp); /* is open */ return(-1); } #endif NCP return(0); } iput (sktp); /* all we wanted to know was was it /dev/net/rawmsg */ if (ncpopnstate == 0) {/* one of ncpkernel or rawkernel must be open*/ u.u_error = ENCPNO; return(-1); } #ifdef NCP if (ncpopnstate > 0) LOMSG = NCPLOMSG; else #endif NCP LOMSG = RAWLOMSG; #ifndef BUFMOD bcopyin (amode, &ropen, sizeof (ropen)); #endif BUFMOD #ifdef BUFMOD for (cp = &ropen, i = 0; i < sizeof ropen; i++ ) *cp++ = fubyte(amode++); #endif BUFMOD mode = ropen.z_mode; host = ropen.z_host; if (!(host.h_net) && (host)) { /* if not long and not anyhost... */ host = stolhost(host.loword.lobyte); /* convert to long */ } host.h_logh = 0; /* ignore logical host field */ mode =% 3; /* get rid of extra mode flags */ low = ropen.z_lomsg; high = ropen.z_himsg; if (high == 0) high = low; mode++; /* convert to form for file struct */ if ((mode < 1) || (mode > 3) || (host < 0) || (low < LOMSG) || (low > high) || (high > HIMSG)) { u.u_error = ERAWINV; return(-1); } if ((fp = falloc()) == 0) return(-1); spl_imp(); for (i = 0; i < 3; i++) fp -> f_netnode [i] = 0; fp -> f_count++; /* fp doesn't go in ncp's file_tab */ fp -> f_flag = (FNET|FRAW|FOPEN|mode); spl0(); for (i = 0; i < 2; i++) { if (mode & (i + 1)) { /* if opening in this mode */ sktp = rawinode (ROPENFLAGS); if (sktp == 0) { u.u_error = ERAWINO; goto nostruct; } fp -> f_netnode [i] = sktp; spl_imp(); if (getrawtab(i, host, low, high, 0)) { u.u_error = ERAWMDUP; goto nostruct; } if (putrawtab(i, host, low, high, sktp) == 0) { u.u_error = ERAWTAB; goto nostruct; } spl0(); } } return(fp); /* success */ nostruct: /* failure */ spl0(); rawrel(fp); fp -> f_flag = fp -> f_count = 0; i = u.u_ar0[R0]; u.u_ofile[i] = 0; return(-1); } /* name: rawclose function: implement the close system call on /dev/net/rawmsg algorithm: if file to be closed was not in use by raw message facility do nothing if this is not last close do nothing release any messages release inodes (rawrel) and file structure return parameters: afp - file pointer of msg to be closed returns: zero - not raw file 1 - raw file, now closed globals: none calls: freemsg rawrel (rawmain.c) called by: netclose (nopcls.c) history: initial coding jsq bbn 9-22-78 use fp -> flag & FRAW check, release fp directly jsq BBN 3-14-79 */ rawclose(afp) struct netfile *afp; { register struct netfile *fp; fp = afp; if (fp == 0) return(0); if (!(fp -> f_flag & FRAW)) return(0); if (fp -> f_count > 2) { --fp -> f_count; return(1); } rawrel (fp); fp -> f_flag = fp -> f_count = 0; return(1); } /* name: rawread function: to do the read system call on /dev/net/rawmsg algorithm: check obvious errors if nothing available to return, just say so (never block if can be avoided) if this is the start of a new message make sure it really is, and find out how long it is save length in v_bytes for future reference find how much to do on this call (lesser of amt asked for and what's in the current message) give that much to user, noting how much actually sent update total bytes available, left in message, and sent this time parameters: aip - pointer to a rawskt (open for reading) returns: zero - not a rawmessage socket one - is, and read done globals: none calls: rawrw (rawmain.c) min bytesout called by: netread (nrdwr.c) history: initial coding by jsq bbn 9-22-78 rawrw call jsq BBN 3-14-79 */ rawread (aip) struct rawskt *aip; { register struct rawskt *sktp; register struct netbuf *nb; register amt; sktp = aip; if ((amt = rawrw(sktp)) >= 0) return(amt); if (sktp -> v_qtotal == 0) return(1); /* nothing to send */ if (sktp -> v_bytes == 0) { /* starting new message */ nb = sktp -> v_msgq -> b_qlink; /* get first buf */ #ifndef BUFMOD amt = (&nb -> b_data[0]) -> integ; /* message length */ #endif BUFMOD #ifdef BUFMOD amt = fbword(nb->b_loc, 0); #endif BUFMOD if ((amt < 2) || (amt > min(MAXMSG + RAWPAD, sktp -> v_qtotal))) { u.u_error = ERAWMLEN; sktp -> v_qtotal = 0; freemsg (sktp -> v_msgq); sktp -> v_msgq = 0; return(1); } sktp -> v_bytes = amt; } amt = min(u.u_count, sktp -> v_bytes); /* to do on this syscall */ amt =- bytesout(&sktp -> v_msgq, u.u_base, amt, 0); /* do it */ sktp -> v_bytes =- amt; /* left in this message */ sktp -> v_qtotal =- amt; /* update total to be read */ u.u_count =- amt; /* asked for but not read this time */ return(1); } /* name: rawwrite function: do write system call on /dev/net/rawmsg algorithm: check obvious errors if starting a new message get a buffer (marked raw) return error if can't get length of message from user (as passed, includes length word and leader length) put a Unix style buffer header in the first buffer marked as used by network, and with contents starting just after self find out how much to get from the user this time and do it if we just got the last of the message from the user, do a little more tinkering with the message and give it to the imp tell user how much we took from him parameters: aip - pointer to a rawskt (open for writing) returns: zero - not a rawmessage socket one - is, and read done globals: none calls: rawrw (rawmain.c) rawbuf (rawtable.c) bcopyin min vectomsg impstrat called by: netwrite (nrdwr.c) history: initial coding jsq bbn 9-22-78 rawrw call jsq BBN 3-14-79 fixed use of v_qtotal so it holds total bytes in que jsq BBN 3-14-79 */ rawwrite(aip) struct rawskt *aip; { register struct rawskt *sktp; register char *firstbuf; register char *nb; int amt; #ifdef BUFMOD int i; #endif BUFMOD sktp = aip; if ((amt = rawrw(sktp)) >= 0) return(amt); if (sktp -> v_bytes == 0) { /* if starting message */ #ifndef BUFMOD bcopyin (u.u_base, &amt, 2); #endif BUFMOD #ifdef BUFMOD firstbuf = &amt; /* using firstbuf as temporary */ nb = u.u_base; /* using nb as temporary */ for (i = 2; i > 0; i--) *firstbuf++ = fubyte(nb++); #endif BUFMOD /* message length (including length word and leader) */ if ((amt < 2) || (amt > MAXMSG)) { u.u_error = ERAWMLEN; return(1); } firstbuf = rawbuf(); /* get a buffer */ if (firstbuf == 0) { return(1); } amt =- 2; u.u_count =- 2; u.u_base =+ 2; sktp -> v_msgq = firstbuf; /* save as current one */ #ifndef BUFMOD firstbuf -> b_len = BUFSIZE; /* putting a sysbuf header */ nb = firstbuf + b_overhead; /* in it starting here */ nb -> b_flags = B_SPEC; /* say owned by network */ nb -> b_addr = nb + BUFSIZE; /* starts after header */ nb -> b_wcount = min((net_b_size - firstbuf -> b_len), amt); /* get bytes in first net buf */ #endif BUFMOD sktp -> v_qtotal = 0; /* nothing is now buffered */ sktp -> v_bytes = amt; /* but this much will be */ } amt = min(sktp -> v_bytes, u.u_count); /* on this syscall */ amt =- vectomsg (u.u_base, amt, &sktp -> v_msgq, 0); /* do it */ sktp -> v_qtotal =+ amt; /* this much in que */ if ((sktp -> v_bytes =- amt) == 0) { /* all of message sent */ #ifndef BUFMOD firstbuf = sktp -> v_msgq -> b_qlink; /* first buffer */ nb = firstbuf + b_overhead; /* and sysbuf header */ nb -> av_forw = firstbuf -> b_qlink; /* point to buf#2 */ nb -> b_dev = sktp -> v_msgq; /* put where imp can release*/ nb -> b_blkno = (firstbuf == sktp -> v_msgq) ? 0 : 1; /* if one buf, set endmsg */ #endif BUFMOD sktp -> v_qtotal = 0; /* nothing is now buffered */ #ifndef BUFMOD impstrat (nb); #endif BUFMOD #ifdef BUFMOD impstrat(sktp->v_msgq); #endif BUFMOD } u.u_count =- amt; /* return amount done this time */ return(1); } /* name: rawrel function: release any buffers & inodes associated with the read or write f_netnode fields of a file structure algorithm: if the given file structure has any such inodes remove any attached buffers remove from the raw connection table release inodes to the system parameters: afp - pointer to a file structure returns: nothing globals: none calls: spl_imp (sys) freemsg (kerbuf.c) getrawtab (rawtable.c) rmrawtab (rawtable.c) called by: rawopen (rawmain.c) rawclose (rawmain.c) rawclean (rawmisc.c) history: initial coding jsq bbn 9-22-78 buffer freeing put here from freerbuf, which was removed, and file freeing bumped up to rawopen and rawclose jsq BBN 3-14-79 */ rawrel(afp) struct netfile *afp; { register struct netfile *fp; register *ip; /* can't be struct inode * */ register *j; int i; int sps; fp = afp; for (i = 0; i < 2; i++) { if (ip = fp -> f_netnode[i]) { sps = PS -> integ; spl_imp(); ip -> v_flags =& ~n_open; /* no longer open */ /* free any buffers */ if (ip -> v_qtotal || ip -> v_bytes) { freemsg (ip -> v_msgq); } ip -> v_bytes = ip -> v_qtotal = ip -> v_msgq = 0; /* remove from connection table */ if (((j = getrawtab(i, ZERO0L, 0, 0, ip)) != 0) && (j != -1)) { rmrawtab(j); } /* free inode */ #ifndef MSG /* point ip at top of inode instead of i_addr array */ ip =- 7; /* (this kludge stolen from daedes) */ #endif MSG /* clean up inode */ for( j = &ip->i_dev; j <= &ip->i_addr[8]; j++ ) *j = 0; /* reset file socket pointer */ fp->f_netnode[i] = 0; /* release inode */ ip->i_flag = ip->i_count = ip->i_lastr = 0; PS -> integ = sps; } } return; /* file is released in rawopen or rawclose, but not rawclean*/ } /* name: rawinode function: find and initialize an inode for use as a raw msg algorithm: look for the inode table for an inode if find one set up first part as in ncp connection inodes set up rawskt for raw msg return pointer to the rawskt else return zero parameters: flags - to go in flags field of rawskt returns: pointer to initialized rawskt or zero if none found calls: spl7() (sys) called by: rawopen (rawmain.c) history: initial coding jsq bbn 9-22-78 */ rawinode(flags) { register struct rawskt *sp; register struct inode *ip; register int sps; for (ip = &inode[0]; ip < &inode[NINODE]; ip++) { if (ip -> i_count == 0) { sps = PS -> integ; spl7(); ip -> i_flag = ILOCK; ip -> i_count = 2; /* 2? */ ip -> i_mode = IALLOC|IFCHR; ip -> i_nlink = 1; ip -> i_dev = ip -> i_number = -2; ip -> i_lastr = -1; ip -> i_size1 = ip -> i_size0 = 0; #ifdef MSG ip -> i_gid = 0; #endif MSG PS -> integ = sps; #ifndef MSG sp = &ip -> i_addr[0]; #endif MSG #ifdef MSG sp = ip; #endif MSG sp -> v_conent = 0; sp -> v_flags = flags; sp -> v_bytes = 0; sp -> v_msgq = 0; sp -> v_qtotal = 0; sp -> v_proc = u.u_procp; return(sp); /* return rawskt pointer */ } } return(0); } /* name: rawrw function: do initialization and obvious error checks for rawread & rawwrite algorithm: if null sktp, give EBADF if not rmi sktp, let netread or netwrite handle it (return 0) if not open, give EBADF put pointer to current proc element in skt if user asked for no transfer, return done return continue parameters: sktp pointer to a RMI skt returns: 1 - all done: return from rawread and netread (resp. write) 0 - let netread or netwrite handle it -1 - let rawread or rawwrite attempt a transfer globals: none calls: nothing called by: rawread, rawwrite history: jsq BBN 3-14-79 */ rawrw(aip) struct rawskt *aip; { register struct rawskt *sktp; sktp = aip; /* is this a valid socket pointer */ if( sktp == 0 ) { u.u_error = EBADF; return(1); } if (!(sktp -> v_flags & n_raw)) return (0); if (!(sktp -> v_flags & n_open)) { u.u_error = EBADF; return(1); } sktp -> v_proc = u.u_procp; if (u.u_count == 0) return(1); return(-1); } /* name: rawlget function: to get a buffer for the leader of a raw message and maybe start read of data algorithm: If we can get a buffer put it on the imp input que find how long the leader was copy it into the buffer, preceding it by the message length so far save the message length if there is any more of the message to read start the imp up again else if there is any more of the message not read, flush it parameters: none returns: 1 - got it 0 - none to get globals: impi_msg - head of the imp message que impi_wcnt - what the imp was told to read last time imp_stat.inpwcnt - what was left implilob - start of the leader which was read impi_mlen - to save the length of the message imp_stat.inpendmsg - did we read the end of the message calls: rawbuf (rawtable.c) impread flushimp called by: imp_input (impio.c) rawih (rawmain.c) history: initial coding by jsq bbn 9-22-78 converted for long or short leaders jsq bbn 12-6-78 */ rawlget(){ register struct netbuf *bp; register char *i, *j; int amt; #ifdef BUFMOD int k; #endif BUFMOD if (bp = rawbuf()) { impi_msg = bp; amt = 2 + ((impi_wcnt + imp_stat.inpwcnt) * 2); if ((amt < 2) || (amt > net_b_size)) { printf("rawlget: bad amount: %d\n", amt); freebuf(bp); impi_msg = 0; flushimp(); return(0); } #ifndef BUFMOD (&bp -> b_data[0]) -> integ = amt; for (i = &bp -> b_data[2], j = implilob; i < &bp -> b_data[amt];) *i++ = *j++; bp -> b_len = impi_mlen = amt; if (imp_stat.inpendmsg == 0) { impread (i, net_b_size - amt); } #endif BUFMOD #ifdef BUFMOD sbword(bp->b_loc,0,amt); for (k = 2, j = implilob; k < amt; k++) sbbyte(bp->b_loc, k, *j++); bp->b_len = impi_mlen = amt; if (imp_stat.inpendmsg == 0) { impread(bp->b_loc, amt, net_b_size - amt); } #endif BUFMOD return(1); } else { if (imp_stat.inpendmsg == 0) { flushimp(); } return(0); } } /* name: rawhh function: to read all of a raw message except the leader algorithm: update the message length with what was just read if we have reached the end of the message if we are flushing free the imp message que of its buffers and are through flushing else put the message length in the first data word of the first buffer of the message if anybody still wants the message give it to them else throw it away (the user must have closed the connection) whether flushing or not, say we're done with this message and start another leader read else if we got the amount read which was last requested if flushing, continue doing so else, tell imp to give us some more else (not endmsg but the imp did not finish reading) must have gotten a spurious interrupt parameters: none returns: nothing globals: impi_mlen - message length impi_wcnt - what the imp was told to read last time imp_stat.inpwcnt - what was left imp_stat.inpendmsg - did we read the end of the message impi_msg - the imp input message que impi_flush - are we flushing impi_con - connection for this message calls: freemsg catmsg implread - defined in imp.h ihbget rawstrat - (rawmain.c) called by: imp_input (impio.c) history: initial coding by jsq bbn 9-22-78, modelled after hh, and with some code taken directly from there. converted for long or short leaders jsq bbn 12-6-78 changed input demultiplexing to use rawent, not rawskt jsq BBN 3-21-79 */ rawhh(){ register char *src, *dest; int cnt; struct netbuf *bp; cnt = (impi_wcnt + imp_stat.inpwcnt) * 2; /* find how much was read*/ impi_mlen =+ cnt; /* add to total for message */ if (impi_msg) impi_msg -> b_len =+ cnt; /* and total for buffer */ if (imp_stat.inpendmsg) { if (impi_flush) { freemsg(impi_msg); impi_flush = 0; } else { bp = impi_msg -> b_qlink; #ifndef BUFMOD (&bp -> b_data[0]) -> integ = impi_mlen; #endif BUFMOD #ifdef BUFMOD sbword(bp->b_loc,0,impi_mlen); #endif BUFMOD if (impi_con) rawstrat(impi_con); else freemsg (impi_msg); } impi_msg = 0; implread(); } else if (imp_stat.inpwcnt == 0) { if (impi_flush) { flushimp(); } else { ihbget(); } } else { printf("\nIMP:Phantom Intrp(Csri=%o)\n", imp_stat.inpstat); } } /* name: rawhostmsg function: to find out if a host and msg for which a leader has come from the imp are in the read raw connection table algorithm: convert msgid from leader into internal form (host was done by impinput) use inrawtab to see if it is in the table if so, return it parameters: none returns: pointer to a rawent on success zero otherwise globals: impi_host imp.link imp.subtype calls: inrawtab (rawtable.c) called by: imp_input (impio.c) rawih (rawmain.c) history: initial coding by jsq bbn 9-22-78 converted for long or short leaders jsq bbn 12-6-78 return rawent, not rawskt jsq BBN 3-31-79 */ rawhostmsg() { register *p; int messid; messid.hibyte = imp.link; /* pick up the whole thing */ messid.lobyte = imp.subtype; /* it's backwards, so fix it */ messid =>> 4; /* make it right adjusted */ messid =& 07777; /* mask off any odd bits */ if (p = inrawtab(0, impi_host, messid)) { return(p); } else { return(0); } } /* name: rawih function: to put raw message imp to host leaders and host to host leaders with data <= 4 bytes on users' ques. algorithm: get the type of the leader just read from the imp if it has a host and msgid see if anybody claims it if no hostmsgid if ELSEMSG is open say send to him if anybody wants the leader if can get a buffer and put the leader in it save user's rawent number give the user the buffer say message has been completely read if there was a hostmsgid (ordinary ih has nothing to do) start another leader read return, letting ih run if there was no hostmsgid. parameters: none returns: 1 - leader completely processed: return from ih 0 - let ih do something with the leader globals: imp.type elseentry (rawnet.h) impi_con impi_mlen impi_msg impi_adr impi_wcnt calls: rawhostmsg (rawmain.c) rawlget (rawmain.c) catmsg implread (imp.h) rawstrat (rawmain.c) called by: ih (impio.c) history: initial coding by jsq bbn 9-22-78 converted for long or short leaders jsq bbn 12-6-78 use impi_con instead of impi_sockt and call rawstrat jsq BBN 3-21-79 */ rawih() { register i; register int *j; int ret; i = imp.type & 0137; j = 0; if ((i == ih_stdmsg) || (i == ih_sideband) || (i == ih_rfnm) || ((i >= ih_hstd) && (i <= ih_ictrans)) || ((i >= ih_rta) && (i <= ih_ready))) { /* has message id? */ if (j = rawhostmsg()) { /* in table? */ ret = 1;/* we always process these completely */ } else { ret = 0;/* may be in ncp connection table */ } } else { /* no message id */ ret = 0; if (elseentry) { j = elseentry; } } if (j) { /* if it goes to anybody we know */ if (rawlget()) {/* and we can buffer it */ rawstrat(impi_con = j); } } #ifdef NCP /* if have completely processed leader or rawkernel open or no ncp */ if (ret || (ncpopnstate < 0)) #endif NCP { /* tell ih to do nothing and start another leader read */ ret = 1; impi_msg = 0; implread(); /* start another leader read */ } return(ret); } /* name: rawstrat function: to put message received from the IMP on user's que according to connection table pointer passed. algorithm: parameters: anent - pointer to a rawent returns: nothing globals: impi_mlen length of following impi_msgq IMP's input message que calls: awake - (awaitr.c) catmsg - (kerbuf.c) called by: rawhh (rawmain.c) rawih - (rawmain.c) history: initial coding jsq BBN 3-21-79 make sure that anent is still a valid rawent, i.e. that its y_rawskt field is not zero. S.Y. Chiu : BBN 22Apr79 */ rawstrat(anent) struct rawent *anent; { register *j; #ifndef MSG register int *sitp; /* used exclusively by await/capac code */ #endif MSG /* It is possible for anent to be an invalid entry in the sense that its * y_rawskt field is 0. This is especially true if rawstrat is called * with impi_con from rawhh. In this case, impi_con is set after an * impread that is previous to the one that causes rawhh to be called. * Between these two impreads, the rawtable entry to which impi_con * points could have been made a free entry by having its y_rawskt field * zeroed. S.Y. Chiu : BBN 22Apr79 */ if (j = anent -> y_rawskt) { j -> v_msgq = catmsg(j -> v_msgq, impi_msg); j -> v_qtotal =+ impi_mlen; #ifndef MSG sitp = j; /* awake user if awtenb */ if (sitp = *(--sitp)) awake (sitp, 0); #endif MSG #ifdef MSG if (j -> itab_p) awake(j -> itab_p, 0); #endif MSG } else freemsg(impi_msg); } #endif RMI