X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb/blobdiff_plain/1e79d00a9f4c2f059c8bd2dc22e601c4ed4065d6..256adf553a043566b5131e718060b918d2075943:/hmsniff.c?ds=inline diff --git a/hmsniff.c b/hmsniff.c index ee14800..2ffb9e1 100644 --- a/hmsniff.c +++ b/hmsniff.c @@ -1,6 +1,6 @@ /* HM-sniffer for HM-CFG-USB * - * Copyright (c) 2013 Michael Gernoth + * Copyright (c) 2013-16 Michael Gernoth * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -29,14 +29,20 @@ #include #include #include +#include #include #include +#include "version.h" #include "hexdump.h" #include "hmcfgusb.h" +#include "hmuartlgw.h" +#include "hm.h" + +static int verbose = 0; /* See HMConfig.pm */ -char *hm_message_types(uint8_t type) +const char *hm_message_types(uint8_t type, uint8_t subtype) { switch(type) { case 0x00: @@ -46,13 +52,20 @@ char *hm_message_types(uint8_t type) return "Configuration"; break; case 0x02: - return "Acknowledge"; + if (subtype >= 0x80 && subtype <= 0x8f) { + return "NACK"; + } else if (subtype == 0x01) { + return "ACKinfo"; + } else if (subtype == 0x04) { + return "AESrequest"; + } + return "ACK"; break; case 0x03: - return "AES"; + return "AESreply"; break; case 0x04: - return "AES-Key"; + return "AESkey"; break; case 0x10: return "Information"; @@ -78,12 +91,28 @@ char *hm_message_types(uint8_t type) case 0x53: return "Water sensor"; break; + case 0x54: + return "Gas sensor"; + break; case 0x58: return "Climate event"; break; + case 0x5a: + return "Thermal control"; + break; + case 0x5e: + case 0x5f: + return "Power event"; + break; case 0x70: return "Weather event"; break; + case 0xca: + return "Firmware"; + break; + case 0xcb: + return "Rf configuration"; + break; default: return "?"; break; @@ -95,43 +124,60 @@ static void dissect_hm(uint8_t *buf, int len) struct timeval tv; struct tm *tmp; char ts[32]; + static int count = 0; int i; gettimeofday(&tv, NULL); tmp = localtime(&tv.tv_sec); memset(ts, 0, sizeof(ts)); strftime(ts, sizeof(ts)-1, "%Y-%m-%d %H:%M:%S", tmp); - printf("%s.%06ld: ", ts, tv.tv_usec); - for (i = 0; i < len; i++) { - printf("%02X", buf[i]); - } - printf("\n"); - printf("Packet information:\n"); - printf("\tLength: %u\n", buf[0]); - printf("\tMessage ID: %u\n", buf[1]); - printf("\tSender: %02x%02x%02x\n", buf[4], buf[5], buf[6]); - printf("\tReceiver: %02x%02x%02x\n", buf[7], buf[8], buf[9]); - printf("\tControl Byte: 0x%02x\n", buf[2]); - printf("\t\tFlags: "); - if (buf[2] & (1 << 0)) printf("WAKEUP "); - if (buf[2] & (1 << 1)) printf("WAKEMEUP "); - if (buf[2] & (1 << 2)) printf("CFG "); - if (buf[2] & (1 << 3)) printf("? "); - if (buf[2] & (1 << 4)) printf("BURST "); - if (buf[2] & (1 << 5)) printf("BIDI "); - if (buf[2] & (1 << 6)) printf("RPTED "); - if (buf[2] & (1 << 7)) printf("RPTEN "); - printf("\n"); - printf("\tMessage type: %s (0x%02x)\n", hm_message_types(buf[3]), buf[3]); - printf("\tMesage: "); - for (i = 10; i < len; i++) { - printf("%02X", buf[i]); - } - printf("\n"); + if (verbose) { + printf("%s.%06ld: ", ts, tv.tv_usec); + + for (i = 0; i < len; i++) { + printf("%02X", buf[i]); + } + printf("\n"); + printf("Packet information:\n"); + printf("\tLength: %u\n", buf[0]); + printf("\tMessage ID: %u\n", buf[1]); + printf("\tSender: %02x%02x%02x\n", buf[4], buf[5], buf[6]); + printf("\tReceiver: %02x%02x%02x\n", buf[7], buf[8], buf[9]); + printf("\tControl Byte: 0x%02x\n", buf[2]); + printf("\t\tFlags: "); + if (buf[2] & (1 << 0)) printf("WAKEUP "); + if (buf[2] & (1 << 1)) printf("WAKEMEUP "); + if (buf[2] & (1 << 2)) printf("CFG "); + if (buf[2] & (1 << 3)) printf("? "); + if (buf[2] & (1 << 4)) printf("BURST "); + if (buf[2] & (1 << 5)) printf("BIDI "); + if (buf[2] & (1 << 6)) printf("RPTED "); + if (buf[2] & (1 << 7)) printf("RPTEN "); + printf("\n"); + printf("\tMessage type: %s (0x%02x 0x%02x)\n", hm_message_types(buf[3], buf[10]), buf[3], buf[10]); + printf("\tMessage: "); + for (i = 10; i < len; i++) { + printf("%02X", buf[i]); + } + printf("\n"); + + printf("\n"); + } else { + if (!(count++ % 20)) + printf(" LL NR FL CM sender recvr payload\n"); - printf("\n"); + printf("%s.%03ld: %02X %02X %02X %02X %02X%02X%02X %02X%02X%02X ", + ts, tv.tv_usec/1000, + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], + buf[7], buf[8], buf[9]); + for (i = 10; i < len; i++) { + printf("%02X", buf[i]); + } + printf("%s(%s)\n", (i>10)?" ":"", hm_message_types(buf[3], buf[10])); + } } struct recv_data { @@ -159,6 +205,7 @@ static int parse_hmcfgusb(uint8_t *buf, int buf_len, void *data) break; case 'R': case 'I': + case 'G': break; default: hexdump(buf, buf_len, "Unknown> "); @@ -168,57 +215,190 @@ static int parse_hmcfgusb(uint8_t *buf, int buf_len, void *data) return 1; } +static int parse_hmuartlgw(enum hmuartlgw_dst dst, uint8_t *buf, int buf_len, void *data) +{ + if (dst == HMUARTLGW_OS) { + if ((buf[0] != HMUARTLGW_OS_ACK) || + (buf[1] != 0x01)) { + hexdump(buf, buf_len, "OS> "); + } + return 0; + } + + if (dst != HMUARTLGW_APP) { + return 0; + } + + switch(buf[0]) { + case HMUARTLGW_APP_RECV: + buf[3] = buf_len - 4; + dissect_hm(buf + 3, buf_len - 3); + case HMUARTLGW_APP_ACK: + break; + default: + hexdump(buf, buf_len, "Unknown> "); + } + + return 1; +} + +void hmsniff_syntax(char *prog) +{ + fprintf(stderr, "Syntax: %s options\n\n", prog); + fprintf(stderr, "Possible options:\n"); + fprintf(stderr, "\t-f\t\tfast (100k/firmware update) mode\n"); + fprintf(stderr, "\t-S serial\tuse HM-CFG-USB with given serial\n"); + fprintf(stderr, "\t-U device\tuse HM-MOD-UART on given device\n"); + fprintf(stderr, "\t-v\t\tverbose mode\n"); + fprintf(stderr, "\t-V\t\tshow version (" VERSION ")\n"); + +} + int main(int argc, char **argv) { - struct hmcfgusb_dev *dev; + struct hm_dev dev = { 0 }; struct recv_data rdata; + char *serial = NULL; + char *uart = NULL; int quit = 0; + int speed = 10; + uint8_t buf[32]; + int opt; + + dev.type = DEVICE_TYPE_HMCFGUSB; + + while((opt = getopt(argc, argv, "fS:U:vV")) != -1) { + switch (opt) { + case 'f': + speed = 100; + break; + case 'S': + serial = optarg; + break; + case 'U': + uart = optarg; + dev.type = DEVICE_TYPE_HMUARTLGW; + break; + case 'v': + verbose = 1; + break; + case 'V': + printf("hmsniff " VERSION "\n"); + printf("Copyright (c) 2013-16 Michael Gernoth\n\n"); + exit(EXIT_SUCCESS); + case 'h': + case ':': + case '?': + default: + hmsniff_syntax(argv[0]); + exit(EXIT_FAILURE); + break; + } + } - hmcfgusb_set_debug(0); + if (dev.type == DEVICE_TYPE_HMCFGUSB) { + hmcfgusb_set_debug(0); + } else { + hmuartlgw_set_debug(0); + } do { memset(&rdata, 0, sizeof(rdata)); rdata.wrong_hmid = 0; - dev = hmcfgusb_init(parse_hmcfgusb, &rdata); - if (!dev) { - fprintf(stderr, "Can't initialize HM-CFG-USB, retrying in 1s...\n"); - sleep(1); - continue; - } - printf("HM-CFG-USB opened!\n"); + if (dev.type == DEVICE_TYPE_HMCFGUSB) { + dev.hmcfgusb = hmcfgusb_init(parse_hmcfgusb, &rdata, serial); + if (!dev.hmcfgusb) { + fprintf(stderr, "Can't initialize HM-CFG-USB, retrying in 1s...\n"); + sleep(1); + continue; + } + printf("HM-CFG-USB opened!\n"); - hmcfgusb_send_null_frame(dev, 1); - hmcfgusb_send(dev, (unsigned char*)"K", 1, 1); + hmcfgusb_send_null_frame(dev.hmcfgusb, 1); + hmcfgusb_send(dev.hmcfgusb, (unsigned char*)"K", 1, 1); + + hmcfgusb_send_null_frame(dev.hmcfgusb, 1); + buf[0] = 'G'; + buf[1] = speed; + hmcfgusb_send(dev.hmcfgusb, buf, 2, 1); + } else { + dev.hmuartlgw = hmuart_init(uart, parse_hmuartlgw, &rdata, 1); + if (!dev.hmuartlgw) { + fprintf(stderr, "Can't initialize HM-MOD-UART!\n"); + exit(1); + } + printf("HM-MOD-UART opened!\n"); + + buf[0] = HMUARTLGW_APP_SET_HMID; + buf[1] = 0x00; + buf[2] = 0x00; + buf[3] = 0x00; + hmuartlgw_send(dev.hmuartlgw, buf, 4, HMUARTLGW_APP); + do { hmuartlgw_poll(dev.hmuartlgw, 500); } while (errno != ETIMEDOUT); + if (speed == 100) { + buf[0] = HMUARTLGW_OS_UPDATE_MODE; + buf[1] = 0xe9; + buf[2] = 0xca; + hmuartlgw_send(dev.hmuartlgw, buf, 3, HMUARTLGW_OS); + } else { + buf[0] = HMUARTLGW_OS_NORMAL_MODE; + hmuartlgw_send(dev.hmuartlgw, buf, 1, HMUARTLGW_OS); + } + } while(!quit) { int fd; if (rdata.wrong_hmid) { printf("changing hmId to 000000, this might reboot the device!\n"); - hmcfgusb_send(dev, (unsigned char*)"A\00\00\00", 4, 1); - rdata.wrong_hmid = 0; - hmcfgusb_send(dev, (unsigned char*)"K", 1, 1); + if (dev.type == DEVICE_TYPE_HMCFGUSB) { + hmcfgusb_send(dev.hmcfgusb, (unsigned char*)"A\00\00\00", 4, 1); + rdata.wrong_hmid = 0; + hmcfgusb_send(dev.hmcfgusb, (unsigned char*)"K", 1, 1); + } else { + buf[0] = HMUARTLGW_APP_SET_HMID; + buf[1] = 0x00; + buf[2] = 0x00; + buf[3] = 0x00; + hmuartlgw_send(dev.hmuartlgw, buf, 4, HMUARTLGW_APP); + } + } + if (dev.type == DEVICE_TYPE_HMCFGUSB) { + fd = hmcfgusb_poll(dev.hmcfgusb, 1000); + } else { + fd = hmuartlgw_poll(dev.hmuartlgw, 60000); } - fd = hmcfgusb_poll(dev, 1); if (fd >= 0) { fprintf(stderr, "activity on unknown fd %d!\n", fd); continue; } else if (fd == -1) { if (errno) { if (errno != ETIMEDOUT) { - perror("hmcfgusb_poll"); + perror("hmsniff_poll"); break; } else { /* periodically wakeup the device */ - hmcfgusb_send_null_frame(dev, 1); + if (dev.type == DEVICE_TYPE_HMCFGUSB) { + hmcfgusb_send_null_frame(dev.hmcfgusb, 1); + } } } } } - hmcfgusb_close(dev); + if (dev.type == DEVICE_TYPE_HMCFGUSB) { + if (dev.hmcfgusb) + hmcfgusb_close(dev.hmcfgusb); + } else { + if (dev.hmuartlgw) + hmuartlgw_close(dev.hmuartlgw); + } } while (!quit); + if (dev.type == DEVICE_TYPE_HMCFGUSB) { + hmcfgusb_exit(); + } + return EXIT_SUCCESS; }