SMACK KISS Mode extension

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.