From: Michael Gernoth Date: Thu, 16 Jul 2015 20:49:14 +0000 (+0200) Subject: Merge branch 'debian' of https://github.com/JSurf/hmcfgusb X-Git-Tag: v0.102~26 X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb/commitdiff_plain/1ee8653afbf410ed34f9dbc18ffe4beaf3c159e4?hp=ed0e161b97bde9ae332c8ed31f118c0c8df816f0 Merge branch 'debian' of https://github.com/JSurf/hmcfgusb Conflicts: README.md --- diff --git a/README.md b/README.md index 907d06b..f0ccc78 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,97 @@ -hmcfgusb -======== - -github mirror of http://git.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb - -I am not the author of this package, i'm just mirroring it here on github, all credits go to -Michael Gernoth http://git.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb - --------------------------------------------------------------------------------------- - - This repository contains utilities to use the HM-CFG-USB(2) (HomeMatic USB Konfigurations-Adapter) from ELV on Linux/Unix by using libusb 1.0. - The HM-CFG-USB can be used to send and receive BidCoS-Packets to control HomeMatic home automation devices (like remote controllable sockets, switches, sensors, ...). - - This repository contains, amongst others, an application, which emulates the HomeMatic LAN configuration adapter-protocol to make it possible to use the HM-CFG-USB in Fhem or as a lan configuration tool for the CCU or the HomeMatic windows configuration software. - - Short hmland HowTo: - Install prerequisites: apt-get install libusb-1.0-0-dev make gcc - Get the current version of this software: hmcfgusb-HEAD-xxxxxxx.tar.gz (xxxxxxx is part of the commit-id. xxxxxxx is just a placeholder for this HowTo, use your value) - Extract the archive: tar xzf hmcfgusb-HEAD-xxxxxxx.tar.gz - Change into the new directory: cd hmcfgusb-HEAD-xxxxxxx - Build the code: make - Optional: Install udev-rules so normal users can access the device: sudo cp hmcfgusb.rules /etc/udev/rules.d/ - Plug in the HM-CFG-USB - Run hmland (with debugging the first time, see -h switch): ./hmland -p 1234 -D - Configure Fhem to use your new HMLAN device: - define hmusb HMLAN 127.0.0.1:1234 - attr hmusb hmId - Updating the HM-CFG-USB firmware to version 0.967: - Compile the hmcfgusb utilities like in the hmland HowTo above (steps 1 to 7) and stay in the directory - Download the new firmware: hmusbif.03c7.enc: wget https://git.zerfleddert.de/hmcfgusb/firmware/hmusbif.03c7.enc - Make sure that hmland is not running - Flash the update to the USB-stick: ./flash-hmcfgusb hmusbif.03c7.enc (You might need to use sudo for this) - (Old) Prebuilt package for OpenWRT (ar71xx): hmcfgusb_1_ar71xx.ipk +This repository contains utilities to use the [HM-CFG-USB(2)][] (HomeMatic USB +Konfigurations-Adapter) from [ELV][] on Linux/Unix by using [libusb 1.0][]. + +The HM-CFG-USB can be used to send and receive [BidCoS-Packets][] to control +[HomeMatic][] home automation devices (like remote controllable sockets, +switches, sensors, ...). + +This repository contains, amongst others, an application, which emulates the +HomeMatic LAN configuration adapter-protocol to make it possible to use the +HM-CFG-USB in [Fhem][] or as a lan configuration tool for the [CCU][] or the +HomeMatic windows configuration software, also supporting devices using +AES-signing like [KeyMatic][]. + +[HM-CFG-USB(2)]: http://www.elv.de/homematic-usb-konfigurations-adapter-1.html +[ELV]: http://www.elv.de/ +[libusb 1.0]: http://www.libusb.org/ +[BidCoS-Packets]: http://homegear.eu/index.php/BidCoS%C2%AE_Packets +[HomeMatic]: http://www.homematic.com/ +[Fhem]: http://fhem.de/ +[KeyMatic]: http://www.elv.de/homematic-funk-tuerschlossantrieb-keymatic-silber-inkl-funk-handsender.html +[CCU]: http://www.elv.de/homematic-zentrale-ccu-2.html + +### Short hmland HowTo: ### + +1. Install prerequisites: + `apt-get install libusb-1.0-0-dev build-essential git` +2. Get the current version of this software (choose **one** option): + * Get the current *release*-version as a .tar.gz: + 1. Download the latest version from the [releases-directory][]. + Version 0.100 is used as an example for the following commands. + 2. Extract the archive: `tar xzf hmcfgusb-0.100.tar.gz` + 3. Change into the new directory: `cd hmcfgusb-0.100` + * Get the current *development*-version via git (can be easily updated with `git pull`): + 1. `git clone git://git.zerfleddert.de/hmcfgusb` + 2. Change into the new directory: `cd hmcfgusb` + * Get the current *development*-version as an archive: + 1. [hmcfgusb-HEAD-xxxxxxx.tar.gz][] (xxxxxxx is part of the commit-id. + xxxxxxx is just a placeholder for this HowTo, use your value) + 2. Extract the archive: `tar xzf hmcfgusb-HEAD-xxxxxxx.tar.gz` + 3. Change into the new directory: `cd hmcfgusb-HEAD-xxxxxxx` +3. Build the code: `make` +4. Optional: Install udev-rules so normal users can access the device: + `sudo cp hmcfgusb.rules /etc/udev/rules.d/` +5. Plug in the HM-CFG-USB +6. Run hmland (with debugging the first time, see `-h` switch): + `./hmland -p 1234 -D` +7. Configure Fhem to use your new HMLAN device: + ``define hmusb HMLAN 127.0.0.1:1234`` + ``attr hmusb hmId `` + +**Important compatibility information:** +If older Fhem-versions (before 2015-06-19) or [Homegear][] before 2015-07-01 +is used to connect to hmland, the `-I` switch might be needed to +impersonate a LAN-interface (this replaces the identity string HM-USB-IF with +HM-LAN-IF). eQ-3 rfd (CCU and configuration software) works without this switch. +Software which needs this will not keep a stable connection open to +hmland without this switch. It was the hardcoded default in versions +< 0.100. + +This incompatibility is needed so connecting software is able to +differentiate between HM-CFG-LAN and HM-CFG-USB. + +[releases-directory]: https://git.zerfleddert.de/hmcfgusb/releases/ +[hmcfgusb-HEAD-xxxxxxx.tar.gz]: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb/snapshot/HEAD.tar.gz +[Homegear]: https://www.homegear.eu/ + +### Updating the HM-CFG-USB firmware to version 0.967: ### + +1. Compile the hmcfgusb utilities like in the hmland HowTo above + (steps 1 to 5) and stay in the directory +2. Download the new firmware: [hmusbif.03c7.enc][]: + `wget https://git.zerfleddert.de/hmcfgusb/firmware/hmusbif.03c7.enc` +3. Make sure that hmland is not running +4. Flash the update to the USB-stick: + `./flash-hmcfgusb hmusbif.03c7.enc` (You might need to use `sudo` for this) + +[hmusbif.03c7.enc]: https://git.zerfleddert.de/hmcfgusb/firmware/hmusbif.03c7.enc + +### Updating HomemMatic devices over the air (OTA) (also for CUL devices): ### + +1. Compile the hmcfgusb utilities like in the hmland HowTo above + (steps 1 to 5) and stay in the directory +2. Download the new firmware from [eQ-3][], in this example the HM-CC-RT-DN + firmware version 1.4 +3. Extract the tgz-file: `tar xvzf hm_cc_rt_dn_update_V1_4_001_141020.tgz` +4. Make sure that hmland is not running +* When using the **[HM-CFG-USB(2)][]**, flash the new firmware to the device + with serial *KEQ0123456*: + `./flash-ota -f hm_cc_rt_dn_update_V1_4_001_141020.eq3 -s KEQ0123456` +* When using a **[culfw][]**-based device (**[CUL][]/[COC][]/...**), flash + the new firmware to the device with serial *KEQ0123456*: + `./flash-ota -f hm_cc_rt_dn_update_V1_4_001_141020.eq3 -s KEQ0123456 -c /dev/ttyACM0` + +[eQ-3]: http://www.eq-3.de/downloads.html +[culfw]: http://culfw.de/culfw.html +[CUL]: http://busware.de/tiki-index.php?page=CUL +[COC]: http://busware.de/tiki-index.php?page=COC diff --git a/flash-hmcfgusb.c b/flash-hmcfgusb.c index 0f0b9ce..a9ff876 100644 --- a/flash-hmcfgusb.c +++ b/flash-hmcfgusb.c @@ -93,11 +93,12 @@ int main(int argc, char **argv) if (!dev->bootloader) { fprintf(stderr, "\nHM-CFG-USB not in bootloader mode, entering bootloader.\n"); - hmcfgusb_enter_bootloader(dev); fprintf(stderr, "\nWaiting for device to reappear...\n"); do { if (dev) { + if (!dev->bootloader) + hmcfgusb_enter_bootloader(dev); hmcfgusb_close(dev); } sleep(1); @@ -165,6 +166,7 @@ int main(int argc, char **argv) firmware_free(fw); hmcfgusb_close(dev); + hmcfgusb_exit(); return EXIT_SUCCESS; } diff --git a/flash-ota.c b/flash-ota.c index 5efd027..754cc29 100644 --- a/flash-ota.c +++ b/flash-ota.c @@ -453,11 +453,12 @@ int main(int argc, char **argv) if (!dev.hmcfgusb->bootloader) { printf("HM-CFG-USB not in bootloader mode, entering bootloader.\n"); - hmcfgusb_enter_bootloader(dev.hmcfgusb); printf("Waiting for device to reappear...\n"); do { if (dev.hmcfgusb) { + if (!dev.hmcfgusb->bootloader) + hmcfgusb_enter_bootloader(dev.hmcfgusb); hmcfgusb_close(dev.hmcfgusb); } sleep(1); @@ -466,10 +467,11 @@ int main(int argc, char **argv) if (dev.hmcfgusb->bootloader) { printf("HM-CFG-USB in bootloader mode, rebooting\n"); - hmcfgusb_leave_bootloader(dev.hmcfgusb); do { if (dev.hmcfgusb) { + if (dev.hmcfgusb->bootloader) + hmcfgusb_leave_bootloader(dev.hmcfgusb); hmcfgusb_close(dev.hmcfgusb); } sleep(1); @@ -736,6 +738,7 @@ int main(int argc, char **argv) switch(dev.type) { case DEVICE_TYPE_HMCFGUSB: hmcfgusb_close(dev.hmcfgusb); + hmcfgusb_exit(); break; case DEVICE_TYPE_CULFW: culfw_close(dev.culfw); diff --git a/hmcfgusb.c b/hmcfgusb.c index 0e11866..652eb42 100644 --- a/hmcfgusb.c +++ b/hmcfgusb.c @@ -58,6 +58,7 @@ static int quit = 0; static int debug = 0; +static int libusb_initialized = 0; /* Not in all libusb-1.0 versions, so we have to roll our own :-( */ static char * usb_strerror(int e) @@ -124,26 +125,33 @@ static libusb_device_handle *hmcfgusb_find(int vid, int pid) { err = libusb_open(dev, &devh); if (err) { fprintf(stderr, "Can't open device: %s\n", usb_strerror(err)); + libusb_free_device_list(list, 1); return NULL; } err = libusb_detach_kernel_driver(devh, INTERFACE); if ((err != 0) && (err != LIBUSB_ERROR_NOT_FOUND)) { fprintf(stderr, "Can't detach kernel driver: %s\n", usb_strerror(err)); + libusb_close(devh); + libusb_free_device_list(list, 1); return NULL; } err = libusb_claim_interface(devh, INTERFACE); if ((err != 0)) { fprintf(stderr, "Can't claim interface: %s\n", usb_strerror(err)); + libusb_close(devh); + libusb_free_device_list(list, 1); return NULL; } + libusb_free_device_list(list, 0); return devh; } } + libusb_free_device_list(list, 1); return NULL; } @@ -250,15 +258,11 @@ static void LIBUSB_CALL hmcfgusb_interrupt(struct libusb_transfer *transfer) if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_TIMED_OUT) { - fprintf(stderr, "Interrupt transfer not completed: %s!\n", usb_strerror(transfer->status)); - quit = EIO; + if (transfer->status != LIBUSB_TRANSFER_CANCELLED) + fprintf(stderr, "Interrupt transfer not completed: %s!\n", usb_strerror(transfer->status)); - if (cb_data && cb_data->dev && cb_data->dev->transfer) { - libusb_free_transfer(cb_data->dev->transfer); - cb_data->dev->transfer = NULL; - free(cb_data); - } - return; + quit = EIO; + goto out; } } else { if (cb_data && cb_data->cb) { @@ -267,14 +271,7 @@ static void LIBUSB_CALL hmcfgusb_interrupt(struct libusb_transfer *transfer) if (!cb_data->cb(transfer->buffer, transfer->actual_length, cb_data->data)) { quit = EIO; - - if (cb_data && cb_data->dev && cb_data->dev->transfer) { - libusb_free_transfer(cb_data->dev->transfer); - cb_data->dev->transfer = NULL; - free(cb_data); - } - - return; + goto out; } } else { hexdump(transfer->buffer, transfer->actual_length, "> "); @@ -284,8 +281,17 @@ static void LIBUSB_CALL hmcfgusb_interrupt(struct libusb_transfer *transfer) err = libusb_submit_transfer(transfer); if (err != 0) { fprintf(stderr, "Can't re-submit transfer: %s\n", usb_strerror(err)); - libusb_free_transfer(transfer); - cb_data->dev->transfer = NULL; + goto out; + } + + return; + +out: + libusb_free_transfer(transfer); + if (cb_data) { + if (cb_data->dev && cb_data->dev->transfer) { + cb_data->dev->transfer = NULL; + } free(cb_data); } } @@ -300,18 +306,23 @@ struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data) int err; int i; - err = libusb_init(NULL); - if (err != 0) { - fprintf(stderr, "Can't initialize libusb: %s\n", usb_strerror(err)); - return NULL; + if (!libusb_initialized) { + err = libusb_init(NULL); + if (err != 0) { + fprintf(stderr, "Can't initialize libusb: %s\n", usb_strerror(err)); + return NULL; + } } + libusb_initialized = 1; devh = hmcfgusb_find(ID_VENDOR, ID_PRODUCT); if (!devh) { devh = hmcfgusb_find(ID_VENDOR, ID_PRODUCT_BL); if (!devh) { fprintf(stderr, "Can't find/open hmcfgusb!\n"); - libusb_exit(NULL); +#ifdef NEED_LIBUSB_EXIT + hmcfgusb_exit(); +#endif return NULL; } bootloader = 1; @@ -321,7 +332,9 @@ struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data) if (!dev) { perror("Can't allocate memory for hmcfgusb_dev"); libusb_close(devh); - libusb_exit(NULL); +#ifdef NEED_LIBUSB_EXIT + hmcfgusb_exit(); +#endif return NULL; } @@ -335,7 +348,9 @@ struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data) perror("Can't allocate memory for hmcfgusb_cb_data"); free(dev); libusb_close(devh); - libusb_exit(NULL); +#ifdef NEED_LIBUSB_EXIT + hmcfgusb_exit(); +#endif return NULL; } @@ -352,17 +367,23 @@ struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data) free(dev); free(cb_data); libusb_close(devh); - libusb_exit(NULL); +#ifdef NEED_LIBUSB_EXIT + hmcfgusb_exit(); +#endif return NULL; } usb_pfd = libusb_get_pollfds(NULL); if (!usb_pfd) { fprintf(stderr, "Can't get FDset from libusb!\n"); + libusb_cancel_transfer(dev->transfer); + libusb_handle_events(NULL); free(dev); free(cb_data); libusb_close(devh); - libusb_exit(NULL); +#ifdef NEED_LIBUSB_EXIT + hmcfgusb_exit(); +#endif return NULL; } @@ -373,10 +394,14 @@ struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data) dev->pfd = malloc(dev->n_usb_pfd * sizeof(struct pollfd)); if (!dev->pfd) { perror("Can't allocate memory for poll-fds"); + libusb_cancel_transfer(dev->transfer); + libusb_handle_events(NULL); free(dev); free(cb_data); libusb_close(devh); - libusb_exit(NULL); +#ifdef NEED_LIBUSB_EXIT + hmcfgusb_exit(); +#endif return NULL; } @@ -529,6 +554,7 @@ void hmcfgusb_close(struct hmcfgusb_dev *dev) if (dev->transfer) { libusb_cancel_transfer(dev->transfer); + libusb_handle_events(NULL); } err = libusb_release_interface(dev->usb_devh, INTERFACE); @@ -537,10 +563,19 @@ void hmcfgusb_close(struct hmcfgusb_dev *dev) } libusb_close(dev->usb_devh); +#ifdef NEED_LIBUSB_EXIT + hmcfgusb_exit(); +#endif free(dev->pfd); free(dev); +} - libusb_exit(NULL); +void hmcfgusb_exit(void) +{ + if (libusb_initialized) { + libusb_exit(NULL); + libusb_initialized = 0; + } } void hmcfgusb_set_debug(int d) diff --git a/hmcfgusb.h b/hmcfgusb.h index 8172622..7bfc53d 100644 --- a/hmcfgusb.h +++ b/hmcfgusb.h @@ -41,4 +41,5 @@ int hmcfgusb_poll(struct hmcfgusb_dev *dev, int timeout); void hmcfgusb_enter_bootloader(struct hmcfgusb_dev *dev); void hmcfgusb_leave_bootloader(struct hmcfgusb_dev *dev); void hmcfgusb_close(struct hmcfgusb_dev *dev); +void hmcfgusb_exit(void); void hmcfgusb_set_debug(int d); diff --git a/hmland.c b/hmland.c index 6b89ece..f1f0e3d 100644 --- a/hmland.c +++ b/hmland.c @@ -1,6 +1,6 @@ /* HM-CFG-LAN emulation for HM-CFG-USB * - * Copyright (c) 2013 Michael Gernoth + * Copyright (c) 2013-15 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 @@ -47,6 +47,10 @@ #define PID_FILE "/var/run/hmland.pid" #define DEFAULT_REBOOT_SECONDS 86400 +#define LAN_READ_CHUNK_SIZE 2048 +/* Don't allow remote clients to consume all of our memory */ +#define LAN_MAX_LINE_LENGTH 4096 +#define LAN_MAX_BUF_LENGTH 1048576 extern char *optarg; @@ -58,6 +62,8 @@ static int reboot_seconds = 0; static int reboot_at_hour = -1; static int reboot_at_minute = -1; static int reboot_set = 0; +static uint8_t *lan_read_buf = NULL; +static int lan_read_buflen = 0; struct queued_rx { char *rx; @@ -283,7 +289,12 @@ static int hmlan_format_out(uint8_t *buf, int buf_len, void *data) format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 3, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE); format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 3, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE); format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 4, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE); - format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 2, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE | FLAG_NL); + if (version < 0x03c7) { + format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 2, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE | FLAG_NL); + } else { + format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 2, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE); + format_part_out(&inpos, (buf_len-(inpos-buf)), &outpos, (sizeof(out)-(outpos-out)), 1, FLAG_FORMAT_HEX | FLAG_COMMA_BEFORE | FLAG_NL); + } if (!reboot_set) { int new_reboot_seconds; @@ -398,72 +409,98 @@ static int hmlan_format_out(uint8_t *buf, int buf_len, void *data) return 1; } -static int hmlan_parse_in(int fd, void *data) +static int hmlan_parse_one(uint8_t *cmd, int last, void *data) { struct hmcfgusb_dev *dev = data; - uint8_t buf[1025]; uint8_t out[0x40]; //FIXME!!! uint8_t *outpos; - uint8_t *inpos; - int i; - int last; - int r; + uint8_t *inpos = cmd; - memset(buf, 0, sizeof(buf)); + outpos = out; - r = read(fd, buf, sizeof(buf)-1); - if (r > 0) { - uint8_t *inend = buf + r; + if (last == 0) + return 1; - inpos = buf; + write_log((char*)cmd, last, "LAN > "); + + memset(out, 0, sizeof(out)); + *outpos++ = *inpos++; + + switch(*cmd) { + case 'S': + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), 0); + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), 0); + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), 0); + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), 0); + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), 0); + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), FLAG_LENGTH_BYTE); + break; + case 'Y': + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), 0); + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), 0); + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), FLAG_LENGTH_BYTE); + break; + case '+': + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), 0); + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), 0); + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), 0); + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), FLAG_LENGTH_BYTE); + default: + parse_part_in(&inpos, (last-(inpos-cmd)), &outpos, (sizeof(out)-(outpos-out)), FLAG_IGNORE_COMMAS); + break; + } - while (inpos < inend) { - uint8_t *instart = inpos; + hmcfgusb_send(dev, out, sizeof(out), 1); - if ((*inpos == '\r') || (*inpos == '\n')) { - inpos++; - continue; - } - - outpos = out; + return 1; +} - last = inend - inpos; +static int hmlan_parse_in(int fd, void *data) +{ + uint8_t *newbuf; + int r; + int i; - for (i = 0; i < last; i++) { - if ((inpos[i] == '\r') || (inpos[i] == '\n')) { - last = i; + newbuf = realloc(lan_read_buf, lan_read_buflen + LAN_READ_CHUNK_SIZE); + if (!newbuf) { + perror("realloc"); + return 0; + } + lan_read_buf = newbuf; + r = read(fd, lan_read_buf + lan_read_buflen, LAN_READ_CHUNK_SIZE); + if (r > 0) { + lan_read_buflen += r; + if (lan_read_buflen > LAN_MAX_BUF_LENGTH) { + if (verbose) + printf("Our buffer is bigger than %d bytes (%d bytes), closing connection!\n", LAN_MAX_BUF_LENGTH, lan_read_buflen); + return -1; + } + while(lan_read_buflen > 0) { + int found = 0; + + for (i = 0; i < lan_read_buflen; i++) { + if ((lan_read_buf[i] == '\r') || (lan_read_buf[i] == '\n')) { + if (i > 0) + hmlan_parse_one(lan_read_buf, i, data); + memmove(lan_read_buf, lan_read_buf + i + 1, lan_read_buflen - (i + 1)); + lan_read_buflen -= (i + 1); + found = 1; break; } + if (i > LAN_MAX_LINE_LENGTH) { + if (verbose) + printf("Client sent more than %d bytes without newline, closing connection!\n", LAN_MAX_LINE_LENGTH); + return -1; + } } - - if (last == 0) - continue; - - write_log((char*)instart, last, "LAN > "); - - memset(out, 0, sizeof(out)); - *outpos++ = *inpos++; - - switch(*instart) { - case 'S': - parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0); - parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0); - parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0); - parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0); - parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0); - parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), FLAG_LENGTH_BYTE); - break; - case 'Y': - parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0); - parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), 0); - parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), FLAG_LENGTH_BYTE); - break; - default: - parse_part_in(&inpos, (last-(inpos-instart)), &outpos, (sizeof(out)-(outpos-out)), FLAG_IGNORE_COMMAS); - break; + if (!found) + break; + newbuf = realloc(lan_read_buf, lan_read_buflen); + if (lan_read_buflen && !newbuf) { + perror("realloc"); + return 0; } - - hmcfgusb_send(dev, out, sizeof(out), 1); + lan_read_buf = newbuf; } } else if (r < 0) { if (errno != ECONNRESET) @@ -686,8 +723,6 @@ static int socket_server(char *iface, int port, int flags) exit(EXIT_FAILURE); } - impersonate_hmlanif = 1; - sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == -1) { perror("Can't open socket"); @@ -750,6 +785,11 @@ static int socket_server(char *iface, int port, int flags) shutdown(client, SHUT_RDWR); close(client); + if (lan_read_buf) + free(lan_read_buf); + lan_read_buf = NULL; + lan_read_buflen = 0; + write_log(NULL, 0, "Connection to %d.%d.%d.%d closed!\n", (client_addr & 0xff000000) >> 24, (client_addr & 0x00ff0000) >> 16, @@ -776,6 +816,7 @@ void hmlan_syntax(char *prog) fprintf(stderr, "\t-D\t\tdebug mode\n"); fprintf(stderr, "\t-d\t\tdaemon mode\n"); fprintf(stderr, "\t-h\t\tthis help\n"); + fprintf(stderr, "\t-I\t\tpretend to be HM-LAN-IF for compatibility with client-software (previous default)\n"); fprintf(stderr, "\t-i\t\tinteractive mode (connect HM-CFG-USB to terminal)\n"); fprintf(stderr, "\t-l ip\t\tlisten on given IP address only (for example 127.0.0.1)\n"); fprintf(stderr, "\t-L logfile\tlog network-communication to logfile\n"); @@ -797,7 +838,7 @@ int main(int argc, char **argv) char *ep; int opt; - while((opt = getopt(argc, argv, "DdhiPp:Rr:l:L:vV")) != -1) { + while((opt = getopt(argc, argv, "DdhIiPp:Rr:l:L:vV")) != -1) { switch (opt) { case 'D': debug = 1; @@ -806,6 +847,9 @@ int main(int argc, char **argv) case 'd': flags |= FLAG_DAEMON; break; + case 'I': + impersonate_hmlanif = 1; + break; case 'i': interactive = 1; break; @@ -857,7 +901,7 @@ int main(int argc, char **argv) break; case 'V': printf("hmland " VERSION "\n"); - printf("Copyright (c) 2013 Michael Gernoth\n\n"); + printf("Copyright (c) 2013-15 Michael Gernoth\n\n"); exit(EXIT_SUCCESS); case 'h': case ':': diff --git a/hmsniff.c b/hmsniff.c index a3cbe7a..1f5d889 100644 --- a/hmsniff.c +++ b/hmsniff.c @@ -125,7 +125,7 @@ static void dissect_hm(uint8_t *buf, int len) 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: "); + printf("\tMessage: "); for (i = 10; i < len; i++) { printf("%02X", buf[i]); } @@ -221,5 +221,7 @@ int main(int argc, char **argv) hmcfgusb_close(dev); } while (!quit); + hmcfgusb_exit(); + return EXIT_SUCCESS; } diff --git a/version.h b/version.h index 0680b90..bec36af 100644 --- a/version.h +++ b/version.h @@ -1 +1 @@ -#define VERSION "0.097-git" +#define VERSION "0.101-git"