,---------[ teledat.sourceforge.net ]---------- | Autor: Felix Schwarz | Webseite: teledat.sourceforge.net | Lizenz: GNU Free Documentation License 1.1 oder neuere (s.u.) | |--------- Changelog --------- | | 20.07.03 fs Anpassung der Protokollnummerierung (v3.0 und v3.1) | `--------- -------------------------------------------------------------------------------- Im folgenden ist das von mir so getaufte "v2.1"-Protokoll allgemein beschrieben. [allgemeine Eigenschaften] Das v2-Protokoll wird von AVM zur Transportsicherung bei der Datenübertragung über das serielle Kabel benutzt. Es ist scheinbar komplett proprietär, auch wenn es Anlehnungen an veröffentlichte RFCs gibt (CRC wird nach RFC 1331 gebildet). Das Protokoll ist verbindungsorientiert (d.h., es gibt eine festgelegte Aufbau-Sequenz) und transportiert auch Statusinformationen zur Telefonanlage wie z.B. die Meldung eines abgehenden oder ankommenden Anrufs. In der Fritz!X PC v1 gibt es ebenfalls eine Art v2-Protokoll. Dieses weicht aber anscheinend leicht vom heute verwendeten v2-Protokoll ab. Vermutlich ist das neue v2 eine Weiterentwicklung des alten, so dass ich das die neuere Version mit v2.1 und die ältere mit v2.1 bezeichne. Da sich die Protokollanalyse zur Zeit auf die neueren Anlagen beschränkt, beziehen sich alle folgenden Informationen auf das v2.1 Protokoll. [Verbindungsaufbau] Zunächst sendet der Client (PC) 0x01 mit 19200 Baud (8N1) an den Server (AVM- Anlage). Diese antwortet ebenfalls mit 0x01 und beide (Server und Client) ändern die Übertragungsgeschwindigkeit auf 115200 Baud. Ab jetzt leuchtet die orangene PC-LED der Anlage und diese sendet alle 10 Sekunden eine Statusmeldung an den Client (die Statusmeldung enthält keinerlei Informationen in Bezug auf den Status der B-Kanäle o.a, scheint also ein reiner "heartbeat" zu sein). [Aufbau der Datenpakete] Die einzelnen Datenpakete beginnen und enden jeweils mit dem Byte 0x7e, die transportierten Inhalte werden durch eine 16 Bit Prüfsumme vor Übertragungsfehlern gesichert. Die Prüfsumme wird gemäß RFC 1331 ("The Point-to-Point Protocol (PPP) for the Transmission of Multi-protocol Datagrams over Point-to-Point Links") gebildet, ein Algorithmus dazu findet sich weiter unten. Um die eindeutige Erkennung der Datenpakete zu gewährleisten, müssen mehrere Zeichen innerhalb der Paket-Grenzen maskiert werden. Auch die Prüfsumme muss ggf. maskiert werden. 0x7d -> 0x7d 0x5d ??? -> 0x7d 0x5c 0x7e -> 0x7d 0x5e 0x11 -> 0x7d 0x31 0x13 -> 0x7d 0x33 Es könnte auch noch andere Ersetzungen geben. Wichtig ist auch die Reihenfolge der Ersetzungen: o Zuerst wird die Prüfsumme gebildet (bei zu versendenden Daten) o Bei zu versendenden Daten werden jetzt die Maskierungen in der oben beschriebenen Reihenfolge vorgenommen. Empfangene Daten werden demaskiert, in dem man die Ersetzungen genau umgekehrt (also von unten nach oben) durchführt. o Bei empfangenen Daten wird erst jetzt die Prüfsumme gebildet. Ein v2-Datenpaket hat also grundsätzlich immer folgendes Format: 0x7e (Daten) (16 Bit CRC) 0x7e Allerdings können v2 Datenpakete nicht unendlich lang sein: Ab einer bestimmten Länge (etwa bei 130 Bytes) werden die Pakete gesplittet ("Multiframes"). Die "angehängten" Pakete beginnen dann mit 0x7e 0xc0 und fahren übergangslos fort. [konkrete Sequenzen] Alle fünf Sekunden sendet die Software folgendes Paket an die Anlage: 7E 20 FF 03 (CRC) 7E Und bekommt darauf prompt die Antwort: 7E 20 FF 03 00 (CRC) 7E TODO: Was passiert, wenn diese Frames nicht gesendet werden, die Antwort abgefangen oder verändert wird? Alle zehn Sekunden schickt die Anlage folgenden Frame: 7E 00 02 DF 01 43 8E 5A 7E ^^ variabel (0x47, 0x39) ohne jedoch eine Antwort zu bekommen. TODO: Was passiert, wenn diese Frames abgefangen, verändert oder zeitversetzt gesendet werden? In welcher Beziehung stehen diese Daten zu obigen v2-Sequenzen? Beeinflussen sie sich gegenseitig? Alle 20 Sekunden schickt die Anlage (wieder ohne Antwort): 7E 00 02 F3 01 09 48 11 7E ^^ variabel, aber identisch mit der folgenden Sektion 7E 00 00 F3 01 09 3E 28 7E ^^ variabel aber mit der oberen Sektion identisch (auch 0x11) 7E 00 02 E1 01 91 A4 39 7E ^^ variabel (auch 0x99) 7E 00 02 DB 01 A5 D7 BB 7E ^^ variabel (auch 0xB9 ) TODO: Was bewirken diese Sequenzen? Was verändert das Abfangen einzelner Pakete? Fakten: (+) Reihenfolge nicht so wichtig, lt. Traces auch 0xF3, 0xF3, 0xE1, 0xDB (+) Die variablen Sektionen scheinen zusammenzuhängen, z.B. 0x09, 0x09, 0x91, 0xA5 oder 0x11, 0x11, 0x99, 0xB9 (+) Die Sektionen ändern sich über die Session hinweg nicht. Alternierend mit den obigen Sequenzen, aber ebenfalls alle 20 Sekunden werden die folgenden Pakete von der Anlage (ohne Antwort) gesendet: 7E 00 02 F3 01 09 48 11 7E ^^ variabel (es fehlt gegenüber oben: 7E 00 00 F3 01 09 3E 28 7E) 7E 00 02 E1 01 91 A4 39 7E ^^ variabel 7E 00 02 DB 01 A5 D7 BB 7E ^^ variabel TODO: Was machen diese Sequenzen? Fakten: (+) Es scheint das gleiche zu gelten wie für der 4er Block (s.o.) [CRC-Algorithmus] #include #define FCSINIT 0xFFFF #define FCSGOOD 0xF0B8 #define FCSSIZE 2 /* 16 bit frame check sum */ /* 16 bit FCS lookup table - RFC1331 */ unsigned short fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; /* PRE: laenge = length(encoded_data) */ int checkcrc (unsigned char* encoded_data, int laenge) { unsigned short fcsval = FCSINIT; int i; for(i=0; i < laenge; i++) { fcsval = (fcsval >>8) ^ fcstab[(fcsval ^ encoded_data[i]) & 0xff]; } if(fcsval == FCSGOOD) { return 1; } else { return 0; } } /* PRE: laenge = length(raw_data) + FCSSIZE */ unsigned char* encode (unsigned char* raw_data, int laenge) { unsigned short fcsval = FCSINIT; int i; for(i=0; i < laenge - FCSSIZE; i++) { fcsval = (fcsval >>8) ^ fcstab[(fcsval ^ raw_data[i]) & 0xff]; } fcsval = ~fcsval; raw_data[i++] = fcsval & 0xff; /* Least significant byte of FCS */ raw_data[i] = (fcsval >> 8) & 0xff; /* MSB of FCS */ return raw_data; } int main(void) { int i; #define SIZE 10 unsigned char data[SIZE] = {0xc0, 0x7e, 0xff, 0xe0, 0x00, 0xdf, 0xed, 0x7e, 0,0}; /* unsigned char* encdata; encdata = encode (data, SIZE); for (i=0; i < SIZE; i++) { printf ("%02x ", encdata[i]); } printf ("\n"); */ if ( checkcrc (encode (data, SIZE), SIZE) ) { printf ("CRC okay\n"); } else { printf ("CRC falsch!\n"); } return 0; } -------------------------------------------------------------------------------- ,---------- [ COPYING ] ----------- | Permission is granted to copy, distribute and/or modify this document | under the terms of the GNU Free Documentation License, Version 1.1 or | any later version published by the Free Software Foundation; with no | Invariant Sections, no Front-Cover Texts and no Back-Cover Texts. A | copy of the license can be obtained under | http://www.gnu.org/licenses/fdl.txt `----------------------------------