view docs/protocol.txt @ 9:a11b330771e0

Fix buffer pointer handling when logging received bytes Actually save the read buffer pointer so we can log the actual protocol bytes read in all cases correctly instead of displaying out of bounds memory in the case where the packet arrives in multiple pieces.
author William Astle <lost@l-w.ca>
date Sat, 30 Jul 2016 10:35:14 -0600
parents cf915ece9e48
children 36c4cda4b6c4
line wrap: on
line source

DRAFT 2014-12-24

Introduction
============

The LWWire protocol is based on the Drivewire protocol originally created by
Boisy Pitre and later expanded by others including Aaron Wolfe.  The
original Drivewire protocol was very simple.  It has since acquired quite a
few bits and bobs that have unfortunate semantics.  Further, Over the years,
Drivewire has accumulated quite a few features which it is not possible for
the client to reliably detect support for.  In addition, the protocol seems
to be ever expanding and accumulating features of limited utility.

The goal of LWWire is to provide a stable core protocol that returns to the
roots of Drivewire 3. The core protocol will support extension negotiation
which allows the client to request specific additional features. This
negotiation must occur before the features can be used.

A secondary goal is for a basic Drivewire client to be able to perform block
I/O on virtual drives even if it does not support the advanced negotiation.

The Protocol
============

Throughout the protocol discussion, the term client will refer to the device
being served, usually a Coco an emulator of some sort. The term server will
refer to the software running on a PC or other similar device that answers
requests from the client.

The LWWire protocol is a master-slave protocol with the client serving the
role of the master. This seems like a reversal but it is necessary because
the client will usually be the device with limited resources which cannot
reliably respond to a byte appearing on the communication channel. Thus, all
transactions are initiated by the client.

All values greater than a single octet are represented in network byte
order, which is otherwise known as big endian. The protocol is octet based.

The first octet of any request is an operation code. This operation code
completely defines the request. Further data may follow the operation code,
depending on the specifc operation. Some operations may require further
round trips as well.

There are two possible types of response from the server. The first is a
standard fixed length response which is defined by the particular operation. 
However, an operation may further define that it returns a variable length
packet.  Such a packet is prefixed by a 16 bit length followed by the actual
data.  Where such a packet is described, the header is not included in the
description.  The variable length return values should be avoided except
when there is a true benefit to using them.  Such a use might be passing
along an IP packet, for instance.

When a client comes online, it must send a "DWINIT" operation. The
driver version/identifier value is not specified by the protocol and must
not change the behaviour of the server. The server will then respond with
its version number. If that number is anything other 0x80, the client must
assume the server is NOT LWWire. If it receives no response, it may continue
with the notion that it might be a Drivewire 3 server.

If the client does receive an indicator that it is talking to LWWire, and it
wishes to use anything other than requests in the Base protocol (anyting in
the "Base Protocol" section below), it MUST initiate a feature negotiation
request and it MUST NOT initiate any usage of the requested feature unless
it receives an ACK response from the server.

If the delay between subsequent bytes in a request is greater 100
milliseconds, the server MUST assume the transaction has failed and treat
it as an unknown transaction. The client MUST implement a similar timeout
to prevent entering into an infinite loop waiting for octets that may never
come. The timeout on the client must be no longer than 1000 milliseconds and
should be no shorter than 100 milliseconds. These timeouts MUST be applied to
ALL octets that are part of the communication stream.

Notwithstanding the above, some operations may specify a longer timeout
which must be respected by that operation.

If the server receives an unknown request OR it detects a timeout receiving
a request, it MUST abort any ongoing request. It MUST then remain silent for
at least 1100 milliseconds to force a timeout on the client. The server MAY
choose to change it's port speed parameters if it detects that the request
may be valid but there is a transmission speed mismatch. This behaviour MUST
NOT be relied upon by the client.


Protocol Operations
===================

Each operation is formatted with a header indicating the operation code in
hexadecimal following by it's name.  Below that is the specification of the
actual request in a table organized by offset within the request. The table
may be absent if the request consists of nothing but the operation code.
Below that is prose describing the operation.


Base Protocol
-------------

The base protocol is always active. It is basically the old Drivewire 3
protocol with no support for wirebug, which turns out to be useful mostly on
paper rather than in real circumstances. Operations are listed in numerical
order.

00 NOOP

This request is a "no-op". The server MUST ignore it and not treat it as an
error.


23 TIME

This request instructs the server to respond with its current date and time.
The response looks as follows:

Octet	Meaning
-----	-------
 0	years since 1900
 1	month (1-12)
 2	day (1-31)
 3	hour (0-23)
 4	minute (0-59)
 5	second (0-60)

This packet roughly corresponds to the return structure for the localtime()
function in C. Note that this request is part of the original Drivewire 3
specification. However, Drivewire 3 specifies only 0-59 for the seconds
value. LWWire allows the value 60 for the seconds value for the rare case
where a leap second is in effect. This is unlikely to ever be a problem in
real deployments since leap seconds can occur at most twelve times per year.

The original Drivewire 3 ipmlementation returned a seventh octet which
encoded the day of the week with Sunday as 0. Since the most common
Drivewire implementation is the Drivewire 4 server which only sends the six
octets and the day of the week value is basically useless, this
specification conforms to the Drivewire 4 implementation.


46 PRINTFLUSH

This operation tells the server to flush its print buffer to its defined
printer or analogue. If it does not support a printer or analogue, or there
is no data to flush, this operation does nothing.


47 GETSTAT

Octet	Meaning
-----	-------
 0	operation code
 1	drive number
 2	GetStat or SetStat code

This operations are specified for compatibility with Drivewire. There is no
response defined. It SHOULD be treated the same as NOOP. The server MAY
choose to log this request but is not required to.


49 INIT

This indicates the server MUST switch to Drivewire 3 mode (if it has one)
or, if it doesn't, switch to Base Protocol mode by disabling all extensions.
It must also clear any statistics counters and state set by any previous
operations.


50 PRINT

Octet	Meaning
-----	-------
 0	operation code
 1	print data octet

This request tells the server to queue the specified print data octet for
output to a printer or some analogue supported by the server. If the server
does not support printing, it will simply ignore this request. The server
MAY choose to flush the print buffer to its printer or analogue at any time,
say because it has not received additional data for some time. The precise
mechanism to do this is not specifically defined.


52 READ

NOTE: this operation should not be used unless a buffered I/O channel of
some kind is in use.  Because the client must read the first response byte
and then decide whether to read 258 further bytes, it is a good idea for the
server to introduce a short delay after the result code, say the length of a
single octet transmission. It is strongly recommended that the READEX
operation be used instead. This operation is supported for compatibility
with old Drivewire implementations.

Octet	Meaning
0	operation code
1	drive number
2-4	LSN requested

This operation requests the server to read a sector from a specified drive. 
In the event of an error, this operation will return a nonzero error code
(see the "Error Codes" section below).  In the event of success, the
response will look as follows:

Octet	Meaning
0	00
1-2	16 bit checksum (simple sum)
3-258	sector data

If the checksum of the received data does not match, the client may choose
to retry with the REREAD operation. The server may choose to treat REREAD as
an alias of READ or it may treat a REREAD without a previous matching READ
as an error.


53 SETSTAT

Octet	Meaning
-----	-------
 0	operation code
 1	drive number
 2	GetStat or SetStat code

This operation is specified for compatibility with Drivewire. There is no
response defined. It SHOULD be treated the same as NOOP. The server MAY
choose to log this request but is not required to.


54 TERM

This request indicates the client is finished with the protocol. It should
be treated the same as INIT (49). It is only specified here for
compatibility with the old Drivewire 3 protocol. New client implementations
should not use this operation.


57 WRITE

Octet	Meaning
-----	-------
0	operation code
1	drive number
2-4	24 bit LSN
5-260	sector data
261-262	16 bit checksum

This operation tells the server to write the specified sector data to the
specified LSN on the specified drive.  Before doing the write, however, the
server will verify the checksum (simple sum of sector octets) and if it
fails, it will not write the sector and return the appropriate error code.
Otherwise, it will attempt the write and return an error code if
appropriate. The error codes are listed in the "Error Codes" section below.

The response to this transaction is a single octet indicating success (00)
or failure (error code). On a checksum error, the client may choose to retry
with the REWRITE operation. On other errors, retrying does not make sense as
the error condition is unlikely to go away.

The server may choose to treat REWRITE as an alias of WRITE. It may also
choose to treat a REWRITE in the absence of a matching WRITE immediately
prior as an error. The client is not obligated to use the REWRITE operation
ever.


5A DWINIT

Octet	Meaning
-----	-------
 0	5A (opcode)
 1	driver version

The driver version above may be a value assigned by the Drivewire
maintainer. However, LWWire does not treat any values specially.

Upon receiving this operation, the server must disable any extensions and
enter into Base Protocol mode. It must also clear any statistics counters
and state set by any previous operations.

The server will respond with the following packet:

Octet	Meaning
-----	-------
 0	server identifier

The server identifier received will be 0x80 if the server supports the
LWWire protocol. If it is anything other than 0x80, the client MUST assume
that the server is NOT LWWire and take whatever action it deems appropriate,
which may include falling back to Drivewire mode.


72 REREAD

See 52 READ.


77 REWRITE

See 57 WRITE.


D2 READEX

Octet	Meaning
-----	-------
 0	operation code
 1	drive number
 2-4	24 bit LSN

The READEX  operation requests the server to read the logical sector
specified by the LSN from the specified drive.  The server will respond with
256 bytes of data.  In the event that an error occured, it will respond with
256 NUL bytes.  Otherwise, it will respond with the actual sector data.

The client will calculate a 16 bit checksum which is a simple sum of all
bytes received.  It will then send that checksum to the server. The server
must permit a longer timeout waiting for the checksum than is otherwise
expected to give the remote side long enough to actually calculate the
checksum. It is recommended that the timeout here be at least 200ms.

Upon receipt of the checksum, the server will verify that it is correct. If
there was an error reading the sector OR the checksum does not match, the
server will return one of the error codes in the "Error Codes" section
below. Otherwise it will return a NUL byte.

In the event of a checksum error, the client may retry the read. Other
errors are unlikely to go away on a retry so retrying in those cases is not
recommended.

The REREADEX request follows an identical flow. The server MAY choose to
treat a REREADEX operation without an immediately preceding READEX operation
as an error. It may choose to avoid re-reading the sector data from the
backing store on the server if it has already read the same LSN for a
previous READEX operation. However, it is also acceptable to simply treat
this as an alias for READEX.


F0 REQUESTEXTENSION

Octet	Meaning
0	operation code
1	extension code (8 bits)

This request is used to request a specific extension, as specified by the
extension code. The server will respond with an ACK response (0x42) or a NAK
response (0x55). Any other response must be considered an error and the
client MUST re-initialize its driver and perform the DWINIT handshake again.
That includes in the case of a timeout.

A NAK means the server does not support the requested extension OR it is
unwilling to make it available for whatever reason.

An ACK means the server has enabled the requested extension for this
particular client.

See the section "Extension Codes" for a list of extension codes.


F1 DISABLEEXTENSION

Octet	Meaning
0	operation code
1	extension code

This request is used to request that the server discontinue usage of a
specific extension.  The server will respond with an ACK (0x42) if it is
able to discontinue the extension. This is the normal response. Some
extensions may not be disablable (which will be specified in the extension
specification). In this case, the server will respond with a NAK (0x55). In
the event of a NAK, the client may choose to continue with the extension
enabled. It may also choose to treat that as an error condition and
re-initiate the DWINIT handshake which will forcibly disable all extensions.

Requesting to disable an extension that is not enabled is not considered
an error since it doesn't require changing the state of anything. In that
case, the ACK response is correct.

See the section "Extension Codes" for a list of extension codes.


F2 REREADEX

See D2 READEX.


F3 EXTENSIONOP

This request indicates that the request is associated with a specific
extension. The second octet is the extension number. Everything after that
is defined entirely by the specified extension. If the specified extension
is not enabled, this request MUST be treated as an unknown request. The
server MUST NOT send a response to any request for any extension that is not
currently active.

This mechanism is provided so that extensions can provide their own
operations without having to select operation codes from the global pool.
Codes can only be assigned in the global pool by the LWWire maintainer.
Codes used inside this request structure can be arbitrarily defined by the
extension without any coordination.


F8 RESET3
FE RESET1
FF RESET2

Either one of these operations should be treated as though the client has
gone away or restarted. These MUST be treated exactly like the INIT (49)
operation.


Error Codes
===========

Code	Meaning
----	-------
00	No error, checksum OK
F3	checksum error
F4	read error (out of bounds, underlying I/O error)
F5	write error
F6	not ready (invalid drive, etc)


Extension Codes
===============

Any code not otherwise listed below is reserved. If you wish to have an
official extension code assigned, contact the maintainer of LWWire to
request one. If you are working on something that does not need general
distribution, or which is only experimental, consider using the private
range listed below.

00	VPORT
01	PACKET
E0-EF	reserved for future extension code expansion
F0-FF	reserved for private extensions and will never be assigned