
SMACK - Protokollbeschreibung
-----------------------------
Version 1.0, Stand 27.02.92
von Jan Schiefer, DL5UE und Dieter Deyke, DK5SG/N0PRA
1. Einführung
Ende 1990 wurde unter den Stuttgarter Packet-Radio-Amateuren erstmals
konkret über die Datensicherung zwischen TNC und WAMPES(*)-Knotenrechner
nachgedacht. Da bei anderen Packet-Knotensystemen bereits Datenverluste
aufgetreten waren, überlegten wir uns, auf welche Art und Weise eine
moeglichst kompatible Erweiterung des KISS-Protokolles um eine Prüfsumme
vorgenommen werden könnte.
Das Resultat dieser Überlegungen bekam den Namen SMACK (Stuttgarts
Modifiziertes Amateurfunk-CRC-KISS. Dieses Dokument soll die Unterschiede
zwischen SMACK und KISS erläutern und Implementierungen auf anderen
Systemen ermöglichen.
2. Was ist KISS?
KISS wurde im Jahre 1986 von Phil Karn, KA9Q vorgeschlagen [1]. Für seine
TCP/IP-Software benötigte er ein Protokoll, daß einen einfachen Zugang zu
Packet-Radio unterhalb der AX.25-Protokollebene ermöglicht. KISS bietet
einen Schicht 2a-Zugang. Aufgaben des TNC sind im wesentlichen nur noch
die Zugriffssteuerung auf die Frequenz (Kanal-Belegt-Erkennung,
P-Persistence-Verfahren) und die Wandlung der synchronen HDLC-Daten
auf dem PR-Kanal in das asynchrone Format der RS232-Schnittstelle.
Das KISS-Protokoll regelt die Abgrenzung einzelner Pakete mit Delimitern,
die Behandlung eventuell im Datenstrom auftretender Delimiter und definiert
einen einfachen Kommandosatz zur Einstellung von TNC-Parametern. Es wurden
Vorkehrungen getroffen, um auch TNCs mit mehreren Packet-Kanälen betreiben
zu können.
3. Modifikation des KISS-Protokolles
Der Hostrechner kommuniziert mit KISS in Form von Paketen. Der Anfang
eines solchen Paketes wird durch den Delimiter FEND gekennzeichnet.
Dann folgt das sogenannte Kommandobyte. Es gibt an, ob es sich um ein
Daten- oder ein Kommandopaket handelt und welches Kommando gemeint ist.
Bis auf eine Ausnahme (Reset-Kommando = 255) benutzen alle Kommandos
nur die unteren 4 Bit dieses Kommandobytes. Dies hat den Sinn, daß
die oberen 4 Bit bei Multi-Kanal-TNCs den Kanal angeben können. So
können 16 Kanäle einzeln parametriert werden.
Da uns weder 16- noch 8-Kanal-TNCs bekannt waren, haben wir das oberste
Bit dieses Kommandobytes zweckentfremdet. Ist es gesetzt, so handelt
es sich bei dem fraglichen Paket um ein Datenpaket mit CRC (nur bei
Datenpaketen findet eine Prüfsummenberechnung statt!).
Bei solchen Paketen wird am Ende des Frames die Prüfsumme angehängt, und
zwar das niederwertige Byte zuerst. Die beiden folgenden Abbildungen zeigen
das Rahmenformat eines Datenpaketes einmal ohne und einmal mit Prüfsumme.
+------+------+------+------+-----+------+------+
| FEND | 0x00 | DATA | DATA | ... | DATA | FEND |
+------+------+------+------+-----+------+------+
KISS-Rahmen ohne Prüfsumme
+------+------+------+------+-----+------+---------+----------+------+
| FEND | 0x80 | DATA | DATA | ... | DATA | CRC LOW | CRC HIGH | FEND |
+------+------+------+------+-----+------+---------+----------+------+
Smack-Rahmen mit Prüfsumme
Es soll hier nochmals wiederholt werden, daß nur Datenpakete CRC-gesichert
werden. Damit wird verhindert, daß keine Kommandos mehr an den TNC geschickt
werden können, wenn sich Host und TNC über CRC/kein CRC uneins sind.
4. Umschalten von KISS auf SMACK
Ein SMACK-TNC arbeitet nach dem Einschalten im KISS-Modus, erzeugt also
keine Pruefsumme. Sobald es das erste Paket mit CRC empfaengt, schaltet
es seine Senderoutinen ebenfalls auf CRC um. Dieser Betriebszustand kann
dann nur noch durch einen Reset verlassen werden. Der Host verhaelt
sich sinngemaess genauso.
Ist jedoch ein KISS-TNC angeschlossen, so wird es CRC-Frames vom Host
aufgrund des ihm unbekannten Kommandobytes verwerfen und normal weiter-
arbeiten.
Diese Methode hat den Vorteil, daß sowohl KISS- als auch SMACK-TNCs ab-
wechselnd an einem Host betrieben werden können, ohne daß ein Umkonfi-
gurieren notwendig ist. Das soll durch eine Darstellung der beiden Fälle
veranschaulicht werden.
---------------------------------------------------------------------------
Fall 1: KISS-TNC
Host TNC
- Sendet ein einziges Paket mit
CRC, schaltet dann seinen Sender
wieder auf Normal-KISS.
- Empfängt einen Rahmen mit dem
für ihn unbekannten Kommando-
byte 0x80 und verwirft ihn.
- Versendet KISS-Daten ohne
Prüfsumme.
- Versendet KISS-Daten ohne
Prüfsumme.
---------------------------------------------------------------------------
Fall 2: SMACK-TNC
Host TNC
- Sendet ein einziges Paket mit
CRC, schaltet dann seinen Sender
wieder auf Normal-KISS.
- Empfängt einen Rahmen mit CRC-
Kennzeichnung, schaltet seinen
Sender auf CRC um.
- Versendet KISS-Daten ohne
Prüfsumme.
- TNC sendet den ersten Rahmen
mit CRC.
- Empfängt einen Rahmen mit CRC-
Kennzeichnung, schaltet seinen
Sender auf CRC um.
- Versendet SMACK-Daten mit
Prüfsumme.
- Versendet SMACK-Daten mit
Prüfsumme.
---------------------------------------------------------------------------
Unabhängig vom Sendezustand (CRC/kein CRC) werden empfangene Rahmen immer
wie folgt behandelt:
Empfangener Rahmen | Aktion
-------------------------------+------------------------
Kein CRC | Rahmen weiterverarbeiten
Mit CRC, Prüfsumme richtig | Rahmen weiterverarbeiten
Mit CRC, Prüfsumme falsch | Rahmen verwerfen
Dieses Protokoll setzt voraus, daß eine KISS-Implementierung ihr unbekannte
Rahmen verwirft. Dies wird in der KISS-Spezifikation [1] gefordert.
4. CRC-Berechnung und Implementierungstips
Dies ist nicht der richtige Ort, um die Theorie der zyklischen Redundanz-
überprüfung (cyclic redundancy check, CRC) zu erläutern. Hierzu sei auf
die Arbeit von Michael Röhner, DC4OX [2] verwiesen. Dieser Abschnitt
schildert nur die für eine Implementierung notwendigen Details.
Als Prüfpolynom wird das CRC16-Polynom verwendet. Dieses hat die Gestalt
16 15 2
X + X + X + 1
Der CRC-Generator wird mit 0 vorbesetzt. Berechnet wird der CRC über alle
Datenbytes einschließlich des Kommandobytes 0x80.
Bekanntlich wird im KISS-Protokoll die Abgrenzung der Rahmen mit dem
FEND-Zeichen (0xc0) durchgeführt. Der Fall, daß dieses Zeichen im
Datenstrom vorkommt, wird gesondert behandelt. Dieser Vorgang wird
SLIP-Encoding genannt.
Der CRC muß berechnet werden, bevor das SLIP-Encoding stattfindet, und
ueberprüft werden, nachdem das SLIP-Decoding stattgefunden hat. Dafür
gib es mehrere Gründe:
- Die CRC Bytes könnten FESC, TFEND, FEND usw enthalten.
- Der SLIP En/Decoder wird in manchen Host-Implementierungen (z.B. WAMPES)
auch unabhängig von KISS benutzt, um beispielsweise die Verbindung zum
Unix-Kernel herzustellen. In diesem Fall wären CRC-Überprüfungen zwar
auch wünschenswert, werden aber von der anderen Seite nicht verstanden.
Die CRCs gehören also logisch zum KISS Layer.
Die Berechnung findet wie folgt statt:
- CRC-Generator mit 0 vorbesetzen.
- Alle Datenbytes nacheinander in den Algorithmus hineintun, einschließlich
der beiden CRC-Bytes.
- Am Ende muß wieder 0 im CRC-Generator stehen. Ist der Wert ungleich 0, so
ist ein Übertragungsfehler aufgetreten und der Rahmen muß verworfen werden.
Verschiedene Algorithmen für den CRC-Generator werden in [2] beschrieben.
Hier sei ein einfacher tabellengesteuerter Algorithmus in der Programmier-
sprache C angegeben, der den CRC eines Puffers (buf) der Länge n berechnet.
/*---------------------------------------------------------------------------*/
static int calc_crc(char *buf, int n)
{
static int crc_table[] = {
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
};
int crc;
crc = 0;
while (--n >= 0)
crc = ((crc >> 8) & 0xff) ^ crc_table[(crc ^ *buf++) & 0xff];
return crc;
}
/*---------------------------------------------------------------------------*/
Die Speicherung der Tabelle benötigt 512 Bytes. Sollte für eine Speicherung
dieser Tabelle das EPROM im TNC zu voll sein, so kann man sie wie folgt zur
Laufzeit aufbauen:
/*---------------------------------------------------------------------------*/
unsigned short Table[256];
const int Rest[8] = { 0xC0C1, 0xC181, 0xC301, 0xC601, 0xCC01, 0xD801,
0xF001, 0xA001 };
main()
{
int i, j;
unsigned short value;
for (i = 0; i < 256; i++) {
value = 0;
for (j = 0; j < 8; j++)
if (i & (1 << j))
value ^= Rest[j];
Table[i] = value;
}
}
/*---------------------------------------------------------------------------*/
Wird dieser Algorithmus in Assembler codiert, so benötigt er deutlich
weniger Platz als die Speicherung der Tabelle selbst.
Die Theorie findet sich wiederum in [2].
5. Implementierungen
Bisher wurde dieses Protokoll in folgenden Systemen implementiert:
- WAMPES
- SMACK, Version 1.3. Diese Software wurde von Jan Schiefer, DL5UE, aus
der von K3MC geschriebenen TNC2-KISS-Implementierung heraus weiter-
entwickelt. Sie wird insbesondere in den TNCs der WAMPES-Knoten
DB0ID (Digipeater Stuttgart) und DB0SAO (Mailbox Stuttgart) eingesetzt
da sie auch einige WAMPES-spezifische Anpassungen enthält.
- Im KISS der NORD-LINK-Firmware, ab TheFirmware Version 2.4
- Für die TCP/IP-Software NOS gibt es von Thommy Osterried, DL9SAU, einen
'Umrüstsatz', der NOS um die SMACK-Fähigkeiten erweitert.
7. Ausblick
Eine wünschenswerte Implementierung dieses Protokolles wäre insbesondere
ein Paket-Treiber nach der 'Packet driver specification' [3]. Damit wäre
eine Umrüstmöglichkeit für alle existierenden NET- und NOS-Versionen
ohne Änderung des Quellcodes gegeben.
Aber auch jede andere Packet-Radio-Software, die KISS-TNCs einsetzt, könnte
von der Fehlersicherheit des CRC profitieren.
Diese Protokollbeschreibung hat vorläufigen Character. Die Autoren
(dl5ue@db0sao, dk5sg@db0sao) sind für Verbesserungsvorschläge, Hinweise
auf Fehler oder sonstige Kommentare dankbar.
(*) WAMPES = Württembergische Amateurfunk Multi-Protokoll-Experimentier-
Software. Ein Softwarepaket unter UNIX, daß vielfältige Protokolle
aus den AX.25-, TCP/IP und NET/ROM-Protokollfamilien implementiert
und, hauptsächlich im Stuttgarter Raum, als Netzknoten eingesetzt
wird. Vergl. [4].
Literatur
[1] Karn, Phil, KA9Q; Proposed "Raw" TNC Functional Spec, 6.8.1986;
veröffentlicht in den USENET-News;
[2] Röhner, Michael, DC4OX; Was ist CRC?; veröffentlicht im Packet-Radio
Mailbox-Netz, Mai 1988
[3] FTP Software, Inc.; PC/TCP Version 1.09 Packet Driver Specification;
Wakefield, MA 1989
[4] Schiefer, Jan, DL5UE; WAMPES - Weiterentwicklung; Vortrags-Skriptum
des 5. überregionalen Packet-Radio-Treffens; Frankfurt 1989;

Pr4Win by Bernd M. Stroj (OE8DJK), last updated on May 7, 1998.