[vz-dev] vzlogger: wieder ein bug im d0-parser

Thorben Thuermer r00t at constancy.org
Thu Jan 10 23:01:30 CET 2013


Hallo,

habe gerade mit einem user im irc einen neuen bug in vzlogger analysiert.

das problem ist, das fuer einen d0-zaehler (Elster A1350) immer zwei
verschiedene werte zusammen auf den kanal geloggt wurden.
der korrekte, und ein anderer, der eigentlich eine andere OBIS-id hat.

die analyse ergab dann:
der zaehler sendet am anfang des telegramms:
0000000: 2f41 4242 345c 4056 352e 3230 2039 3036  /ABB4\@V5.20 906
0000010: 3036 3839 330d 0a02 3332 2e37 2e30 2832  06893...32.7.0(2

d.h. die start-zeile, dann \r\n (0x0d, 0x0a), dann ein byte: 0x02,
und erst dann die ascii-ziffern der ersten obis-ID.
0x02 ist laut doku des zaehlerherstellers in "<STX>" "start of text" marker.

das problem ist nun, das vzlogger davon nix weiss, und dieses byte zur
obis-id zaehlt:

src/protocols/d0.c:
204             case IDENTIFICATION:        /* IDENTIFICATION has 16 bytes */
205                 if (byte == '\r' || byte == '\n') { /* detect line end */
207                     context = OBIS_CODE;    /* set new context: IDENTIFICATION -> OBIS_CODE */

215             case OBIS_CODE:
216                 if ((byte != '\n') && (byte != '\r'))
218                     if (byte == '(') {
222                         context = VALUE;
223                     }
224                     else obis_code[byte_iterator++] = byte;

254             case END_LINE:
258                         print(log_debug, "Parsed reading (OBIS code=%s, value=%s, unit=%s)", mtr, obis_code, value, unit);
260                         obis_parse(obis_code, &rds[number_of_tuples].identifier.obis);

dies ergibt dann in strace die schoene ausgabe:
[pid  5124] write(1, "[Jan 10 21:27:04][mtr0] Parsed reading (OBIS code=\00232.7.0, value=237.3, unit=V)\n", 80) = 80
(man beachte das \002, das in einem terminal wohl einfach verschwinden wuerde)

und weiter:
src/obis.c:
106 int obis_parse(const char *str, obis_id_t *id) {
121     for (int i = 0; i < len; i++) {
122         byte = str[i];
124         if (isdigit(byte)) {
127         else {
128             if (byte == '-' && field < A) {     /* end of field A */
140             else {
141                 return ERR;

d.h., wenn das erste byte auf nix matcht (was bei 0x02 vorkommt),
dann schreibt obis_parse nix in den rueckgabepuffer und liefert ERR zurueck,
aber wie wir oben sehen:
src/protocols/d0.c:
260                         obis_parse(obis_code, &rds[number_of_tuples].identifier.obis);
wird der rueckgabewert ignoriert!

wir haben jetzt also nicht initialisierte daten fuer den obis-identifier...!
und im fall dieses users waren diese daten immer 0xff, bzw. 255:
[mtr0] Reading: id=255-255:255.255.255*255 value=237.30 ts=1357849624.292"

weiter dann:
src/threads.c
 82         /* insert readings into channel queues */
 83         foreach(mapping->channels, ch, channel_t) {
 88                 if (reading_id_compare(mtr->protocol, rds[i].identifier, ch->identifier) == 0) {
 93                     print(log_info, "Adding reading to queue (value=%.2f ts=%.3f)", ch, rds[i].value, tvtod(rds[i].time))
 94                     reading_t *rd = buffer_push(&ch->buffer, &rds[i]);
src/reading.c:
 54 int reading_id_compare(meter_protocol_t protocol, reading_id_t a, reading_id_t b) {
 56         case meter_protocol_d0:
 58             return obis_compare(a.obis, b.obis);
src/obis.c:
177 int obis_compare(obis_id_t a, obis_id_t b) {
178     for (int i = 0; i < 6; i++) {
179         if (a.raw[i] == b.raw[i] || a.raw[i] == 0xff || b.raw[i] == 0xff ) {
180             continue; /* skip on wildcard or equal */
190     return 0; /* equal */

durch diese (etwas zweifelhafte?!) wildcard-logik matcht die fehlerhaft
geparsete id dann immer, und wird fuer jeden channel submitted!

soweit die analyse...

- Thorben


More information about the volkszaehler-dev mailing list