TCP driver documentation -- GDMR, May/June 1987. -------------------------------------------------- TCPDriver is a pseudo-device driver for VMS intended to interface beteween a protocol handler and its clients. It was designed primarily for use with TCP and UDP, but could doubtless be adapted for other protocols. The driver has a master (unit 0) and a number of slaves (as determined when the pseudo-device is connected). Althought the basic functionality of the two sides is similar, the master side has a number of additional operations which allow it to control the state of the slaves. When a slave is first connected it remains unavailable until enabled by the master, at which time it can perform only "open" and "claim" functions. Once a successful "open" has been performed the slave can perform read, write and close operations. Typically, once the slave has been closed the master would make it unavailable for a time (reinitialising queues as a side effect) before again making it available. From the slaves' point of view, read requests always result in data being transferred from the master; from the master's point of view, read requests can pair up with any of the slave requests except a read, with the slave unit and function code being returned in the master's IOSB. The device is connected by a sequence of commands of the form: $ r Sys$System:SysGen Load TCPDriver Connect TCP0 /NoAdapter /Driver=TCPDriver /MaxUnits=8 Connect TCP1 /NoAdapter /Driver=TCPDriver Connect TCP2 /NoAdapter /Driver=TCPDriver Connect TCP3 /NoAdapter /Driver=TCPDriver Connect TCP4 /NoAdapter /Driver=TCPDriver Connect TCP5 /NoAdapter /Driver=TCPDriver Connect TCP6 /NoAdapter /Driver=TCPDriver Connect TCP7 /NoAdapter /Driver=TCPDriver Connect UDP0 /NoAdapter /Driver=TCPDriver /MaxUnits=4 Connect UDP1 /NoAdapter /Driver=TCPDriver Connect UDP2 /NoAdapter /Driver=TCPDriver Connect UDP3 /NoAdapter /Driver=TCPDriver where "MaxUnits" and the number of slave units can be chosen by the system manager to control the number of network ports available to users. Note that "MaxUnits" includes the master unit (unit 0). Function codes accepted ----------------------- IO$_Create open/define connection to remote peer P1 = address of connect data P2 = size of connect data P5 = error status (master only) P6 = slave unit-ID (master only) IO$M_Abort use provided error status (P5, master only) If the master supplies connect data it is copied into the slave's buffer to indicate the identity of the peer; otherwise the slave's buffer remains untouched. Note that after the slave's IO$_Create request has been communicated to the master it remains pending until the master issues a corresponding IO$_Create. As a side effect of the slave's request being completed successfully (IO$M_Abort unset) the slave unit is enabled for read and write operations. Additionally, the most significant bit (16_8000) of the third word of the master's IOSB (slave unit word) will be set if the slave process has SysPrv privilege. IO$_ReadVBlk (general data transfer) IO$_ReadLBlk IO$_ReadPBlk P1 = address of buffer P2 = length of buffer Both sides receive data written by the other by means of this request; in addition, the master receives notification of slave opens and claims. The third word of the master's IOSB contains the slave unit-ID of the corresponding unit, while the fourth word contains the slave's IO request code. Note that slave write requests will be mapped on to IO$_WritePBlk. IO$_WriteVBlk (general data transfer) IO$_WriteLBlk IO$_WritePBlk P1 = address of buffer P2 = length of buffer P6 = slave unit-ID (master only) IO$_WritEOF close connection P6 = user unit-ID (master only) The other side's (next) read request will receive SS$_EndOfFile as its completion status. Note that the exact function of the "close" request is as determined by the protocol: no change of device status is implied. IO$_ReadPrompt claim port P4 = allocated port (master only) P5 = error status (master only) P6 = user unit-ID (master only) IO$M_Abort use provided error status (P5) The slave's request is passed on to the master and then remains pending until the master issues a corresponding IO$_ReadPrompt request. The port allocated by the master process is returned as the second word of the slave's IOSB. Note that any slave function modifiers will be passed on to the master; additionally, the most significant bit (16_8000) of the third word of the master's IOSB (slave unit word) will be set if the slave process has SysPrv privilege. IO$_SenseMode query number of units (no parameters) The SysGen device parameter MaxUnits is copied into each UCB$L_DevDepend field, whence it can be read either by an IO$_SenseMode operation or by requesting the DevDepend option of Sys$GetDvI. IO$_SetMode make (un)available P5 = error status P6 = user unit-ID IO$M_Mount make available IO$M_DMount make unavailable IO$M_Qualified block/unblock IO$M_Abort use provided error status (P5) This operation, which is available only to the master, is used to control the availability of slave units. One or other of the modifiers IO$M_Mount or IO$M_DMount must be specified. If IO$M_Mount is specified the slave unit is put online, hence becoming available for use by users. If IO$M_DMount is specified the slave is marked offline, thus causing any future requests to be rejected; additionally, any pending requests are returned with either SS$_Abort status or the status provided in P5. If IO$M_Qualified is specified the operations instead become respectively unblock and block, thereby allowing the master to impose flow control on the slaves' write requests. There is also an implied request made when Sys$Cancel or Sys$DAssgn is called, either explicitly or as part of image/process rundown. If a slave unit's reference count goes to zero then the master side receives notification via a pseudo-request with SS$_Hangup status and "function code" IO$_Unload. If any cancel or deassign operation is performed by the master then ALL slave units are marked offline and ALL pending requests are returned with SS$_Hangup status; this is intended for the extreme case of the death of the master process, and deliberate invocation should probably be done sparingly. Status codes returned --------------------- The following status codes are returned in the IOSB: SS$_Abort, SS$_BadParam, SS$_BufferOvF, SS$_Cancel, SS$_DevOffLine, SS$_EndOfFile, SS$_Hangup, SS$_Normal, and anything which the master side chooses to send back by means of open and claim responses and IO$_SetMode!IO$M_DMount. Note that the master can receive SS$_BadParam for an open or claim response operation as a result of the slave request being cancelled in the interim. Slave operations for TCP/IP --------------------------- The normal sequence of operations for TCP/IP use (devices TCP1 .. TCPn) is first to obtain a local port (unless acting as a server, when a known port number would be used); then open the connection to the peer socket; then read and write data until the connection has been closed in both directions, as indicated by receiving SS$_EndOfFile status and issuing an IO$_WritEOF request. Note that any DAssgn operation will be interpreted as an abort request until such time as the connection has been properly closed in both directions, after which it will be ignored. A "privileged port" (in the UNIX sense) may be requested by means of the function code modifier IO$M_Qualified. The connect data takes the form of three longwords (12 bytes), being the remote address, the remote port and the local port respectively. If the remote address is specified an "active open" is performed, while if it is unspecified a "passive open" takes place with the connection remaining in the Listen state until an inbound connect request arrives; in this latter case the connect data returned by the master will fully specify the remote peer. Slave operation for UDP/IP -------------------------- UDP/IP use (devices UDP1 .. UDPn) is similar to that for TCP/IP. However, since UDP is connectionless the open/close operations become instead define/undefine peer operations. To send a datagram to a remote UDP socket the define operation must first be performed, after which any datagrams sent using the write operation will be posted to the remote peer. Inbound datagrams will be delivered to the slave which has defined the remote peer appropriately (if there are no such slaves it will be thrown away). If the remote address is unspecified (zero) then it is taken to be wild; however, if any non-broadcast datagrams arrive it will be implicitly defined to correspond to the sending socket. Note that the current definition may be determined by issuing a define request with the function modifier IO$M_ReadCSR.