The slip.asm program is an implementation of SLIP in assembly language. SLIP is described in RFC-1055 and is "a nonstandard for transmission of IP datagrams over serial lines" as described in the title of that document. SLIP was the forerunner of PPP and is in most ways inferior. However, SLIP is extremely simple to implement and so, it is still used sometimes for small devices.
The purpose of this code is to show how one might implement SLIP in assembly language. The two routines defined in the code, send_packet and recv_packet correspond exactly to the C routines of the same name that are described in the SLIP RFC.
It should be noted that these are only pieces of a program and not a whole program. At some future date, I will probably post a whole program which uses these methods.
(It may be useful to follow the source code as you're reading this description.)
SLIP itself is quite simple, and so is the implementation of it in either C or assembly language. The basic notion is that there are two special characters -- SLIP_ESC and SLIP_END. SLIP_END is sent only at the beginning and end of each packet. To assure that those are indeed the only places that byte appears, it is escaped, i.e. replaced with a two-byte sequence, whenever a datagram contains that byte. The mechanism is to replace all occurrences of SLIP_END in the datagram with the two-byte sequence, SLIP_ESC + SLIP_ESC_END. The other character that is escaped is the SLIP_ESC byte itself so that the receiving end doesn't interpret the byte as the beginning of an escape sequence. It is converted from SLIP_ESC to SLIP_ESC + SLIP_ESC_ESC.
Although it is actually a protocol violation to have a SLIP_ESC byte followed by something other than either a SLIP_ESC_END or SLIP_ESC_ESC, the original RFC-1055 and this assembly language implementation both interpret SLIP_ESC + byte as though it were just byte; i.e. the SLIP_ESC is discarded.
In the RFC-1055 code and in this source code, there are two functions which are referenced but not defined. In this assembly language implementation, they are named SEND_CHAR and RECV_CHAR. These are macros which need to be supplied by the user of the routines, but the code as written includes two bare minimum macros to illustrate the kind of thing that needs to be there.
SEND_CHAR receives one argument which must be byte-sized (either a constant or a register). Calling this macro should cause the indicated byte to be sent to the distant end.
The RECV_CHAR macro receives no arguments and should return the next received character in the AL register. Note that the macro should not return until there is a byte received. This is not the way the sample macro is written, so it is important to understand the difference if you actually intend to use this code.
Also important is register usage. If you redefine RECV_CHAR and SEND_CHAR you must take care not to alter registers that are in use by the rest of the routines in which they exist. In the case of send_packet, this means that the DS, SI and CX registers must be preserved. Within recv_packet, all of those plus the BX register must also be preserved.
Microsoft's MASM assumes that labels are local to procedures. Borland's TASM supports this notion, too, but with the restriction that the local labels are preceded with @@. That's why it is legal to define a label @@bailout in both the send_packet and the recv_packet procs.
I have used this notion for many years in my x86 assembly source code and it works very well. However, not all assemblers support this feature. If yours is one that does not, I would recommend either changing to a more capable assembler or to manually changing all of the labels to be unique. In the long run, the first option will save you lots of time and aggravation over the second.
Ed Beroset
Last modified: Fri Jan 16 22:27:28 2004 |