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.