Version in base suite: 0.14.54.1 Base version: knxd_0.14.54.1 Target version: knxd_0.14.69-2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/k/knxd/knxd_0.14.54.1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/k/knxd/knxd_0.14.69-2.dsc .gitignore | 153 +++++++ .mailmap | 8 .travis.yml | 25 - AUTHORS | 26 + Makefile.am | 2 README.md | 144 ++----- configure.ac | 13 debian/.gitignore | 17 debian/changelog | 75 +++ debian/control | 8 debian/copyright | 24 - debian/knxd.install.systemd | 1 debian/patches/dgit-changes | 243 ++++++++++++ debian/patches/series | 1 debian/rules | 11 debian/source/format | 2 doc/inifile.rst | 103 ++++- install-debian.sh | 25 - m4/ccforbuild.m4 | 4 src/backend/Makefile.am | 8 src/backend/eibnetrouter.cpp | 6 src/backend/eibnettunnel.cpp | 2 src/backend/fpace.cpp | 5 src/backend/fqueue.cpp | 3 src/backend/ft12.cpp | 2 src/backend/monitor.cpp | 68 +++ src/backend/monitor.h | 40 ++ src/backend/nat.cpp | 2 src/backend/ncn5120.cpp | 3 src/backend/tpuart.cpp | 54 ++ src/backend/tpuart.h | 3 src/client/go/Makefile.am | 7 src/client/lua/Makefile.am | 7 src/client/pascal/Makefile.am | 7 src/client/python/Makefile.am | 7 src/client/ruby/Makefile.am | 7 src/examples/vbusmonitor1time.c | 6 src/include/eibtypes.h | 2 src/libserver/Makefile.am | 2 src/libserver/cemi.cpp | 30 + src/libserver/cemi.h | 1 src/libserver/client.cpp | 4 src/libserver/client.h | 15 src/libserver/cm_ip.cpp | 8 src/libserver/cm_ip.h | 4 src/libserver/eibnetip.cpp | 69 +-- src/libserver/eibnetip.h | 61 ++- src/libserver/eibnetserver.cpp | 28 - src/libserver/eibnetserver.h | 3 src/libserver/eibusb.cpp | 3 src/libserver/emi1.cpp | 2 src/libserver/emi_common.cpp | 3 src/libserver/lowlevel.cpp | 4 src/libserver/lowlevel.h | 1 src/libserver/lpdu.h | 4 src/libserver/retry.cpp | 11 src/libserver/retry.h | 1 src/libserver/router.cpp | 52 ++ src/libserver/server.cpp | 44 +- src/libserver/server.h | 27 - src/libserver/tcptunserver.cpp | 776 ++++++++++++++++++++++++++++++++++++++++ src/libserver/tcptunserver.h | 148 +++++++ src/libserver/tunchannel.cpp | 401 ++++++++++++++++++++ src/libserver/tunchannel.h | 151 +++++++ src/libserver/usblowlevel.cpp | 4 src/server/Makefile.am | 2 src/tools/common.c | 23 - src/tools/eibread-cgi.c | 68 +-- src/tools/eibwrite-cgi.c | 24 - src/tools/knxtool.c | 8 src/usb/findknxusb.cpp | 1 systemd/Makefile.am | 2 systemd/knxd-net.socket.in | 12 systemd/knxd.conf | 4 systemd/knxd.service.in | 6 systemd/knxd.udev | 47 ++ tools/list_AUTHORS | 2 77 files changed, 2761 insertions(+), 419 deletions(-) diff -Nru knxd-0.14.54.1/.gitignore knxd-0.14.69/.gitignore --- knxd-0.14.54.1/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/.gitignore 2024-12-16 15:40:26.000000000 +0000 @@ -0,0 +1,153 @@ +/debian/ +*~ +*.swp +*.la +*.a +*.o +*.lo +*.pyc +*.pyo +*.deps/ +Makefile.in +Makefile +.libs +/COPYING +/INSTALL +/aclocal.m4 +/compile +/config.guess +/config.h +/config.h.in +/config.log +/config.status +/config.sub +/configure +/confdefs.h +/depcomp +/doc +/install-sh +/libtool +/libev/ +/libfmt/ +/ltmain.sh +/missing +/path.h +/autom4te.cache +/autom4te.cache/ +/stamp-h1 +/version.h +/m4/libtool.m4 +/m4/ltoptions.m4 +/m4/ltsugar.m4 +/m4/ltversion.m4 +/m4/lt~obsolete.m4 +/src/client/c/gen/ +/src/client/cs/EIBConnection.cs +/src/client/cs/EIBConnection.post +/src/client/cs/result.inc +/src/client/lua/EIBConnection.lua +/src/client/lua/gen +/src/client/lua/gen.inc +/src/client/lua/result.inc +/src/client/pascal/EIBD.pas +/src/client/pascal/gen +/src/client/pascal/gen.inc +/src/client/pascal/genh +/src/client/pascal/genh.inc +/src/client/pascal/result.inc +/src/client/perl/EIBConnection.p +/src/client/perl/EIBConnection.p1 +/src/client/perl/EIBConnection.pm +/src/client/perl/EIBConnection.post +/src/client/perl/result.inc +/src/client/php/EIBConnection.php +/src/client/php/EIBConnection.post +/src/client/php/eibclient.php +/src/client/php/result.inc +/src/client/python/EIBConnection.py +/src/client/python/gen +/src/client/python/gen.inc +/src/client/python/result.inc +/src/client/ruby/gen +/src/client/ruby/gen.inc +/src/client/ruby/result.inc +/src/client/ruby/EIBConnection.rb +/src/client/go/EIBConnection.go +/src/client/go/gen +/src/client/go/gen.inc +/src/client/go/result.inc + +/src/examples/busmonitor1 +/src/examples/busmonitor2 +/src/examples/busmonitor3 +/src/examples/groupcacheclear +/src/examples/groupcachedisable +/src/examples/groupcacheenable +/src/examples/groupcachelastupdates +/src/examples/groupcacheread +/src/examples/groupcachereadsync +/src/examples/groupcacheremove +/src/examples/grouplisten +/src/examples/groupread +/src/examples/groupreadresponse +/src/examples/groupresponse +/src/examples/groupsocketlisten +/src/examples/groupsocketread +/src/examples/groupsocketswrite +/src/examples/groupsocketwrite +/src/examples/groupsresponse +/src/examples/groupswrite +/src/examples/groupwrite +/src/examples/madcread +/src/examples/maskver +/src/examples/mmaskver +/src/examples/mpeitype +/src/examples/mprogmodeoff +/src/examples/mprogmodeon +/src/examples/mprogmodestatus +/src/examples/mprogmodetoggle +/src/examples/mpropdesc +/src/examples/mpropread +/src/examples/mpropscan +/src/examples/mpropscanpoll +/src/examples/mpropwrite +/src/examples/mread +/src/examples/mrestart +/src/examples/msetkey +/src/examples/mwrite +/src/examples/mwriteplain +/src/examples/progmodeoff +/src/examples/progmodeon +/src/examples/progmodestatus +/src/examples/progmodetoggle +/src/examples/readindividual +/src/examples/vbusmonitor1 +/src/examples/vbusmonitor1poll +/src/examples/vbusmonitor1time +/src/examples/vbusmonitor2 +/src/examples/vbusmonitor3 +/src/examples/writeaddress +/src/examples/xpropread +/src/examples/xpropwrite + +/src/server/knxd +/src/server/knxd_args + +/src/tools/eibread-cgi +/src/tools/eibwrite-cgi +/src/tools/knxtool +/src/tools/bcu/bcuaddrtab +/src/tools/bcu/bcuread +/src/tools/eibnet/eibnetdescribe +/src/tools/eibnet/eibnetsearch + +/src/usb/findknxusb + +/systemd/*.service +/systemd/*.socket + +/tools/test_inih +/src/examples/eibread-cgi +/src/examples/eibwrite-cgi +/src/examples/knxtool +/systemd/knxd.service.exp diff -Nru knxd-0.14.54.1/.mailmap knxd-0.14.69/.mailmap --- knxd-0.14.54.1/.mailmap 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/.mailmap 2024-12-16 15:40:26.000000000 +0000 @@ -0,0 +1,8 @@ +Stefan Hoffmeister +Michael Markstaller +Joerg Mattiello +Patrik Pfaffenbauer +Timo Wingender +Matthias Urlichs +Matthias Urlichs +Lars Tolkmitt diff -Nru knxd-0.14.54.1/.travis.yml knxd-0.14.69/.travis.yml --- knxd-0.14.54.1/.travis.yml 2018-04-23 11:45:20.000000000 +0000 +++ knxd-0.14.69/.travis.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -language: cpp -compiler: gcc -dist: trusty -script: - - sh -x bootstrap.sh - - env CFLAGS="-Wall -Wextra -Wno-reorder" CPPFLAGS="-Wall -Wextra -Wno-reorder" ./configure --disable-systemd - - make - - sh tools/test.sh -notifications: - email: - on_success: change - on_failure: always -sudo: false -install: - - if [ "$CXX" = "g++" ]; then export CXX="g++-5" CC="gcc-5"; fi -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-5 - - g++-5 - - libev-dev - - libusb-1.0-0-dev - - strace diff -Nru knxd-0.14.54.1/AUTHORS knxd-0.14.69/AUTHORS --- knxd-0.14.54.1/AUTHORS 2020-04-05 12:49:03.000000000 +0000 +++ knxd-0.14.69/AUTHORS 2024-12-16 15:40:26.000000000 +0000 @@ -1,44 +1,66 @@ Alphabetical list of surnames of everyone who ever committed to this repository. -Auto-generated from tools/list_AUTHORS and .mailmap +Auto-generated by tools/list_AUTHORS and .mailmap +dimnij <63244636+dimnij@users.noreply.github.com> +akellai Michael Albert Enrik Berkhan bmxp +HeySora Thomas Dallmair +Tobias Deiminger +Matthias Fechner Meik Felser Sven Fischer Andreas Frisch Eduard Fuchs StalderT +Simón Golpe <33048138+Golpe82@users.noreply.github.com> +Marcus Haehnel hari2 Richard Hartmann +Richard Hartmann +henfri Stefan Hoffmeister +Matthias J-N-K Marc Joliet +jrester jsauermann Elias Karakoulakis +Michael Kefeder Michael Kefeder +Trond Kjeldås Trond Kjeldås Claus Klingberg Martin Koegler +Gregor Krmelj Ole Krüger Harald +Harald Leithner Tobias Lorenz +MagicBear Michael Markstaller +Michael Markstaller Joerg Mattiello Race666 Sebastian +akellai Ole buergi Patrik Pfaffenbauer Joakim Plate Stephan Reinhard +root +Richard Schleich shakaraba smaiLee SystemTera +Lars Tolkmitt Henning Treu Othmar Truniger Matthias Urlichs +Sergey V. Lobanov Christian Wicke Timo Wingender -Matthias Fechner +Paweł Żabiełowicz diff -Nru knxd-0.14.54.1/Makefile.am knxd-0.14.69/Makefile.am --- knxd-0.14.54.1/Makefile.am 2022-10-25 12:27:52.000000000 +0000 +++ knxd-0.14.69/Makefile.am 2024-12-16 15:40:26.000000000 +0000 @@ -2,7 +2,6 @@ ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST=SubmittingPatches .gitignore tools/version.sh -CONFIGURE_DEPENDENCIES=debian/changelog ## rebuild when the version changes BUILDDIRS = @@ -34,7 +33,6 @@ @echo "" # update version number -configure: debian/changelog config.h: configure test: all diff -Nru knxd-0.14.54.1/README.md knxd-0.14.69/README.md --- knxd-0.14.54.1/README.md 2022-10-25 12:27:52.000000000 +0000 +++ knxd-0.14.69/README.md 2024-12-16 15:40:26.000000000 +0000 @@ -4,9 +4,13 @@ KNX is a very common building automation protocol which runs on dedicated 9600-baud wire as well as IP multicast. ``knxd`` is an advanced router/gateway which runs on any Linux computer; it can talk to all known KNX interfaces. -This is the `debian` branch, which contains Debian packaging. -Use this branch if you're installing knxd on Debian, Ubuntu or one of their -derivatives. +# STOP if you install on Debian (or Ubuntu or …) + +Debian/Ubuntu packaging has moved to the ``debian`` branch. Please use that +branch (by way of ``git checkout debian``) if you're following some (outdated …) +installation instructions for Debian, Ubuntu or their derivatives. + +In the ``debian`` branch, this file contains build instructions for Debian. # Stable version @@ -53,10 +57,6 @@ ### see https://github.com/knxd/knxd/blob/v0.12/README.md for earlier changes -* 0.14.51 - - * Added a "heartbeat-timeout" option to the tunnel server - * 0.14.41 * speed up CGI initial setup (a lot) @@ -198,89 +198,35 @@ ## Building -On Debian/Ubuntu: - - sudo apt-get install git-core - - # get the source code - git clone -b debian https://github.com/knxd/knxd.git - - # now build+install knxd - sh knxd/install-debian.sh - - # … and if you'd like to update knxd: - rm knxd*.deb - sh knxd/install-debian.sh - -The `knxd/install-debian.sh` script should work without problems on any -up-to-date Debian or Debian-derived system. If not, please do this before -filing an issue: - -* Verify that your system is 100% up-to-date. +When in doubt, please check out the branch corresponding to your Linux +distribution's flavor, and read this section there. -* Verify that you did not pin any packages, either via ``aptitude`` or - ``/etc/apt/preferences``. +This part covers "manual" installation. -* Otherwise, installing the file ``knxd-build-deps_*.deb`` with ``dpkg`` - and resolving its dependencies via ``aptitude -f install`` should fix - whatever happens to be wrong with your system. Remove the build-deps - package *without* auto-removing the ``-dev`` packages it depends on, then - try again. + # first, install build tools and dependencies. You need git, autotools, and gcc/g++. + #: check your Linux distribution's documentation if you don't know how + # You also need a "knxd" user. -* If that doesn't work either, open an issue. Add the log from the - previous step. + # get the source code + git clone https://github.com/knxd/knxd.git -Instructions for other flavors of Linux distributions should be in the -corresponding branches. Additions welcome. + # build+install knxd + cd knxd + git checkout main + sh bootstrap.sh + ./configure --help + ./configure --your-chosen-options + make + make install + cd .. -On MacOS or Windows, please use a Linux VM. + # Now switch to the "knxd" user and start the daemon. If you would like to submit patches for Mac OSX or Windows, go ahead and create a pull request, but please be prepared to maintain your code. -### Test failures - -The build script runs a comprehensive set of tests to make sure that knxd -actually works. It obviously can't test code that talks to directly-connected -hardware, but the core parts are exercised. - -If the test fails: - -* Do you have a default route? - -* Are you filtering packets to multicast address 224.99.98.97, or to UDP port 3671? - -* Is something on your network echoing multicast packets? (Yes, that happens.) -If you can't figure out the cause of the failure, please open an issue. - -### Daemon Configuration - -Daemon configuration differs depending on whether you use systemd. -If "systemctl status" emits something reasonable, you are. - -If you use systemd, the configuration file is ``/etc/knxd.conf``. -Socket activation is used for the default IP and Unix sockets -(port 6720 and /run/knx, respectively). - -Without systemd, on Debian, edit ``/etc/default/knxd``. - -The default Unix socket is ``/run/knx``. -Old eibd clients may still use ``/tmp/eib`` to talk to knxd. -You need to either change their configuration, or add "-u /tmp/eib" -to knxd's options. -(This was the default for "-u" before version 0.11.) - - -### New ".ini" configuration file - -knxd is typically started with "knxd /etc/knxd.ini". - -The file format is documented in "doc/inifile.rst". You might want to use -the program "/usr/lib/knxd_args" to create it from previous versions' -command-line arguments. - -### Adding a TPUART USB interface +### Adding a TPUART USB interface (serial, USB) If you attach a (properly programmed) TUL (http://busware.de/tiki-index.php?page=TUL) to your computer, it'll show up as ``/dev/ttyACM0``. This is a problem because (a) it's owned by root, thus knxd can't access it, and (b) if you ever add another serial interface that uses the same driver, knxd will use the wrong device. @@ -314,13 +260,18 @@ You'll have to update your rule if you ever plug your TPUART into a different USB port. This is intentional. -### Adding any other USB interface + +### Adding some other USB interface These interfaces should be covered by the `udev` file knxd installs in ``/lib/udev/rules.d``. Simply use ``-b usb:`` to talk to it, assuming you don't have more than one. -### Adding a TPUART serial interface to the Raspberry Pi +If your interface isn't covered by our udev file, please add its vendor+product +and send us a patch. + + +### Adding a TPUART (Pi HAT) interface to the Raspberry Pi On the Raspberry Pi 2 and 3 the console is /dev/ttyAMA0. The udev line is: @@ -337,20 +288,21 @@ This rule creates a symlink ``/dev/knx1`` which points to the console. The knxd configuration will use that symlink. -On the Raspberry Pi 2 and 3 you need to disable the serial console. Edit ``/boot/cmdline.txt`` and -remove the ``console=ttyAMA0`` entry. Then reboot. +On the Raspberry Pi 2 and 3 you need to disable the kernel's serial console. +Edit ``/boot/cmdline.txt`` and remove the ``console=ttyAMA0`` entry. Then reboot. On the Raspberry Pi 3, the serial console is on ``ttyAMA1`` by default. -However, that is a software-driven serial port – the single hardware serial +However, that is a software-driven serial port – the hardware serial interface is used for Bluetooth on the Pi3. Varying CPU speed causes this -port to be somewhat unreliable. If this happens, disable Bluetooth by adding +port to be somewhat unreliable. You should disable Bluetooth by adding ``` dtoverlay=pi3-disable-bt ``` to ``/boot/config.txt``, run ``systemctl disable hciuart``, and -reboot. The TPUART module is now back on ``ttyAMA0``. +reboot. The console and the TPUART module is now back on ``ttyAMA0``. + ## Migrating to 0.14 @@ -435,23 +387,27 @@ ## Contributions -* Any contribution is *very* welcome -* Please use Github and create a pull request with your patches +* Contributions are *very* welcome +* Please use Github and create a pull request with your patches. * Please see SubmittingPatches to correctly Sign-Off your code and add yourself to AUTHORS (`tools/list_AUTHORS > AUTHORS`) -* Adhere to our [coding conventions](https://github.com/knxd/knxd/wiki/CodingConventions). The git archive includes a helpful .vimrc file if you use VIM. +* Adhere to our [coding conventions](https://github.com/knxd/knxd/wiki/CodingConventions). +* The git archive includes a helpful .vimrc file if you use VIM. ### Compensation – personal statement KNX development is not a simple matter and requires both time and dedicated hardware for tests. The ETS software isn't exactly cheap, either, and -there is no free replacement. (I'd like to change that.) +there is no free replacement. (I'd like to change that, but time is fleeting.) Thus, wearing my hat as the (current) main author, I (Matthias Urlichs) would like to ask you to consider contributing to knxd's development. -* paypal: matthias@urlichs.de -* bitcoin: 1G2NKavCVt2adxEUZVG437J2tHvM931aYd -* SEPA: DE25760400610535260401 @ COBADEFFXXX +* [Github](https://github.com/sponsors/smurfix) +* [LiberaPay](https://liberapay.com/knxd/) +* Paypal: urlichs@m-u-it.de +* SEPA: DE34430609671145580100 @ GENODEM1GLS +* Ethereum: please ask +* Bitcoin: please don't waste power I can issue a commercial invoice if required. diff -Nru knxd-0.14.54.1/configure.ac knxd-0.14.69/configure.ac --- knxd-0.14.54.1/configure.ac 2021-03-16 18:42:55.000000000 +0000 +++ knxd-0.14.69/configure.ac 2024-12-16 15:40:26.000000000 +0000 @@ -42,14 +42,17 @@ dnl Oh come on Apple ... case $host in *-*-darwin*) - link_all_option="-all_load" - no_link_all_option="-noall_load" + link_force_option=",-force_load" + link_all_option="" + no_link_all_option="" ;; *) - link_all_option="--whole-archive" - no_link_all_option="--no-whole-archive" + link_force_option="" + link_all_option=",--whole-archive" + no_link_all_option=",--no-whole-archive" ;; esac +AC_SUBST(LINK_FORCE,$link_force_option) AC_SUBST(LINK_ALL,$link_all_option) AC_SUBST(NO_LINK_ALL,$no_link_all_option) @@ -338,7 +341,7 @@ src/Makefile src/include/Makefile src/client/Makefile src/examples/Makefile src/libserver/Makefile src/server/Makefile src/backend/Makefile src/client/def/Makefile src/client/c/Makefile src/client/java/Makefile src/client/php/Makefile src/client/cs/Makefile src/client/perl/Makefile src/client/python/Makefile src/client/pascal/Makefile src/client/ruby/Makefile src/client/lua/Makefile src/client/go/Makefile -src/usb/Makefile src/tools/Makefile systemd/Makefile systemd/knxd.service systemd/knxd.socket +src/usb/Makefile src/tools/Makefile systemd/Makefile systemd/knxd.service systemd/knxd.socket systemd/knxd-net.socket ]) dnl src/tools/eibnet/Makefile src/tools/bcu/Makefile AC_OUTPUT diff -Nru knxd-0.14.54.1/debian/.gitignore knxd-0.14.69/debian/.gitignore --- knxd-0.14.54.1/debian/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/debian/.gitignore 2024-12-17 08:40:21.000000000 +0000 @@ -0,0 +1,17 @@ +/tmp +/knxd-examples +/knxd-dev +/knxd-tools +/knxd +/*.log +/*.debhelper +/*.substvars +/knxd.udev +/files +/knxd.install +/knxd.service +/knxd.socket +/knxd-net.socket +/autoreconf.after +/autoreconf.before +/debhelper-build-stamp diff -Nru knxd-0.14.54.1/debian/changelog knxd-0.14.69/debian/changelog --- knxd-0.14.54.1/debian/changelog 2022-10-25 12:28:34.000000000 +0000 +++ knxd-0.14.69/debian/changelog 2024-12-17 08:40:21.000000000 +0000 @@ -1,3 +1,54 @@ +knxd (0.14.69-2) stable; urgency=medium + + * Fix install location + + -- Matthias Urlichs Tue, 17 Dec 2024 09:40:21 +0100 + +knxd (0.14.69-1) unstable; urgency=medium + + * knxd-net.socket + + -- Matthias Urlichs Mon, 16 Dec 2024 16:40:51 +0100 + +knxd (0.14.68-1) unstable; urgency=medium + + * Merge + * Various bugfixes + * Bump Standards-Version to 4.7.0.1 + + -- Matthias Urlichs Wed, 13 Nov 2024 10:08:04 +0100 + +knxd (0.14.66-2) unstable; urgency=medium + + * Merge + + -- Matthias Urlichs Mon, 28 Oct 2024 21:40:42 +0100 + +knxd (0.14.65-1) unstable; urgency=medium + + * Merge + + -- Matthias Urlichs Fri, 11 Oct 2024 17:10:37 +0200 + +knxd (0.14.64-1) unstable; urgency=medium + + * Merge + + -- Matthias Urlichs Fri, 11 Oct 2024 17:06:58 +0200 + +knxd (0.14.63.1) unstable; urgency=medium + + * Merge + * Remove C++ line-based comments from C files. Closes: #1075116 + + -- Matthias Urlichs Wed, 03 Jul 2024 15:05:04 +0200 + +knxd (0.14.56.2) unstable; urgency=medium + + * Merge + + -- Matthias Urlichs Thu, 10 Nov 2022 19:19:25 +0100 + knxd (0.14.54.1) unstable; urgency=medium * Merge. Closes: #1004310 @@ -5,6 +56,30 @@ -- Matthias Urlichs Tue, 25 Oct 2022 14:28:34 +0200 +knxd (0.14.62-1) unstable; urgency=medium + + * Merge + + -- Matthias Urlichs Wed, 12 Jun 2024 12:37:49 +0200 + +knxd (0.14.60-1) unstable; urgency=medium + + * Merge + + -- Matthias Urlichs Tue, 09 Jan 2024 15:45:39 +0100 + +knxd (0.14.59-1) unstable; urgency=medium + + * Merge + + -- Matthias Urlichs Tue, 18 Jul 2023 19:05:00 +0200 + +knxd (0.14.54-1) unstable; urgency=medium + + * Merge + + -- Matthias Urlichs Sat, 29 Jan 2022 14:40:31 +0100 + knxd (0.14.53-1) unstable; urgency=medium * Merge diff -Nru knxd-0.14.54.1/debian/control knxd-0.14.69/debian/control --- knxd-0.14.54.1/debian/control 2022-10-25 12:27:52.000000000 +0000 +++ knxd-0.14.69/debian/control 2024-12-17 08:40:21.000000000 +0000 @@ -6,20 +6,20 @@ autoconf, automake, libtool, git, libusb-1.0-0-dev (>= 1.0.9), - pkg-config, + pkgconf | pkg-config, libsystemd-dev (>= 228) | libsystemd-daemon-dev (>= 200) | base-files (<< 8), libev-dev, libfmt-dev | libfmt3-dev | cmake (>= 2.8.12), libfmt-dev | libfmt3-dev | git, Build-Conflicts: libsystemd-daemon-dev (<< 200) -Standards-Version: 4.3.0.1 +Standards-Version: 4.7.0.1 Homepage: https://github.com/knxd/knxd -Vcs-Git: https://github.com/knxd/knxd.git +Vcs-Git: https://github.com/knxd/knxd.git -b debian Vcs-Browser: https://github.com/knxd/knxd Package: knxd Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, libusb-1.0-0 (>= 1.0.10), lsb-base, adduser +Depends: ${shlibs:Depends}, ${misc:Depends}, libusb-1.0-0 (>= 1.0.10), adduser Replaces: eibd, eibd-server Conflicts: eibd, eibd-server Description: daemon to access the KNX bus diff -Nru knxd-0.14.54.1/debian/copyright knxd-0.14.69/debian/copyright --- knxd-0.14.54.1/debian/copyright 2022-10-25 12:27:52.000000000 +0000 +++ knxd-0.14.69/debian/copyright 2024-12-17 08:40:21.000000000 +0000 @@ -4,20 +4,7 @@ Files: * Copyright: - © 2005-2019 knxd project members; see AUTHORS file -License: GPL-2.0+ - -Files: contrib/arch-build-system/* -Copyright: - © 2015 Ole Krueger - © 2015-2018 Claus Klingberg -License: GPL-2.0+ - -Files: contrib/gentoo/* -Copyright: - © 2015 Marc Joliet - © 2015-2017 Michael Kefeder - © 2015-2017 Matthias Urlichs + © 2005-2024 knxd project members; see AUTHORS file License: GPL-2.0+ Files: contrib/udev/* @@ -29,7 +16,7 @@ Files: debian/* Copyright: © 2014 Timo Wingender - © 2015-2019 Matthias Urlichs + © 2015-2024 Matthias Urlichs License: GPL-2.0+ Files: m4/ax_cxx_compile_stdcxx.m4 @@ -78,13 +65,6 @@ © 2017 Joerg Mattiello License: GPL-2.0+ -Files: rpm/* -Copyright: - © 2015 Juergen Sauermann - © 2016-2017 Michael Kefeder - © 2017 Matthias Urlichs -License: GPL-2.0+ - Files: src/backend/ncn5120.cpp Copyright: © 2014-2015 Patrik Pfaffenbauer diff -Nru knxd-0.14.54.1/debian/knxd.install.systemd knxd-0.14.69/debian/knxd.install.systemd --- knxd-0.14.54.1/debian/knxd.install.systemd 2022-10-25 12:27:52.000000000 +0000 +++ knxd-0.14.69/debian/knxd.install.systemd 2024-12-17 08:40:21.000000000 +0000 @@ -1,2 +1,3 @@ etc/knxd.conf +lib/systemd/system/knxd-net.socket usr/lib/sysusers.d diff -Nru knxd-0.14.54.1/debian/patches/dgit-changes knxd-0.14.69/debian/patches/dgit-changes --- knxd-0.14.54.1/debian/patches/dgit-changes 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/debian/patches/dgit-changes 2024-12-17 08:40:21.000000000 +0000 @@ -0,0 +1,243 @@ +From: +Subject: Debian changes + +The Debian packaging of knxd is maintained in git, using a workflow +similar to the one described in dgit-maint-merge(7). +The Debian delta is represented by this one combined patch; there isn't a +patch queue that can be represented as a quilt series. + +A detailed breakdown of the changes is available from their canonical +representation -- git commits in the packaging repository. +For example, to see the changes made by the Debian maintainer in the first +upload of upstream version 1.2.3, you could use: + + % git clone https://git.dgit.debian.org/knxd + % cd knxd + % git log --oneline 1.2.3..debian/1.2.3-1 -- . ':!debian' + +(If you have dgit, use `dgit clone knxd`, rather than plain `git clone`.) + +We don't use debian/source/options single-debian-patch because it has bugs. +Therefore, NMUs etc. may nevertheless have made additional patches. + +--- + +diff --git a/.gitignore b/.gitignore +index bcbe340..951d7cf 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,4 +1,3 @@ +-/debian/ + *~ + *.swp + *.la +diff --git a/Makefile.am b/Makefile.am +index e66b4b2..9ecf9da 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2,6 +2,7 @@ AUTOMAKE_OPTIONS=1.9 + ACLOCAL_AMFLAGS = -I m4 + EXTRA_DIST=SubmittingPatches .gitignore tools/version.sh + ++CONFIGURE_DEPENDENCIES=debian/changelog + ## rebuild when the version changes + + BUILDDIRS = +@@ -33,6 +34,7 @@ help HELP: + @echo "" + + # update version number ++configure: debian/changelog + config.h: configure + + test: all +diff --git a/README.md b/README.md +index 930e190..b9f1749 100644 +--- a/README.md ++++ b/README.md +@@ -4,13 +4,14 @@ knxd [![Build Status](https://travis-ci.org/knxd/knxd.svg)](https://travis-ci.or + KNX is a very common building automation protocol which runs on dedicated 9600-baud wire as well as IP multicast. + ``knxd`` is an advanced router/gateway which runs on any Linux computer; it can talk to all known KNX interfaces. + +-# STOP if you install on Debian (or Ubuntu or …) ++# STOP if you are not on Debian (or Ubuntu or …) + +-Debian/Ubuntu packaging has moved to the ``debian`` branch. Please use that +-branch (by way of ``git checkout debian``) if you're following some (outdated …) +-installation instructions for Debian, Ubuntu or their derivatives. ++This is the ``debian`` branch, which includes Debian-specific packaging and ++some minor related changes. If you're using some other Linux flavor, please ++check out the corresponding branch, or use ``main`` for "manual" ++installation to ``/usr/local``. + +-In the ``debian`` branch, this file contains build instructions for Debian. ++Otherwise see the installation instructions, below. + + # Stable version + +@@ -57,6 +58,10 @@ to knxd's options. + + ### see https://github.com/knxd/knxd/blob/v0.12/README.md for earlier changes + ++* 0.14.51 ++ ++ * Added a "heartbeat-timeout" option to the tunnel server ++ + * 0.14.41 + + * speed up CGI initial setup (a lot) +@@ -198,33 +203,94 @@ please also see: [eibd(war bcusdk) Fork -> knxd](http://knx-user-forum.de/forum/ + + ## Building + +-When in doubt, please check out the branch corresponding to your Linux +-distribution's flavor, and read this section there. ++Run these steps as normal user, not as root. + +-This part covers "manual" installation. ++On Debian/Ubuntu: + +- # first, install build tools and dependencies. You need git, autotools, and gcc/g++. +- #: check your Linux distribution's documentation if you don't know how +- # You also need a "knxd" user. ++ sudo apt-get install git + + # get the source code +- git clone https://github.com/knxd/knxd.git ++ git clone -b debian https://github.com/knxd/knxd.git ++ ++ # now build+install knxd ++ sh knxd/install-debian.sh ++ ++That's all (well, except for configuring knxd). ++ ++For updating: + +- # build+install knxd + cd knxd +- git checkout main +- sh bootstrap.sh +- ./configure --help +- ./configure --your-chosen-options +- make +- make install +- cd .. ++ git pull ++ sh install-debian.sh + +- # Now switch to the "knxd" user and start the daemon. ++The `knxd/install-debian.sh` script should work without problems on any ++up-to-date Debian or Debian-derived system. If not, please do this before ++filing an issue: ++ ++* Verify that your system is 100% up-to-date. ++ ++* Verify that you did not pin any packages, either via ``aptitude`` or ++ ``/etc/apt/preferences``. ++ ++* Otherwise, installing the file ``knxd-build-deps_*.deb`` with ``dpkg`` ++ and resolving its dependencies via ``aptitude -f install`` should fix ++ whatever happens to be wrong with your system. Remove the build-deps ++ package *without* auto-removing the ``-dev`` packages it depends on, then ++ try again. ++ ++* If that doesn't work either, open an issue. Add the log from the ++ previous step. ++ ++Instructions for other flavors of Linux distributions should be in the ++corresponding branches. Additions welcome. ++ ++On MacOS or Windows, please use a Linux VM. + + If you would like to submit patches for Mac OSX or Windows, go ahead + and create a pull request, but please be prepared to maintain your code. + ++### Test failures ++ ++The build script runs a comprehensive set of tests to make sure that knxd ++actually works. It obviously can't test code that talks to directly-connected ++hardware, but the core parts are exercised. ++ ++If the test fails: ++ ++* Do you have a default route? ++ ++* Are you filtering packets to multicast address 224.99.98.97, or to UDP port 3671? ++ ++* Is something on your network echoing multicast packets? (Yes, that happens.) ++ ++If you can't figure out the cause of the failure, please open an issue. ++ ++### Daemon Configuration ++ ++Daemon configuration differs depending on whether you use systemd. ++If "systemctl status" emits something reasonable, you are. ++ ++If you use systemd, the configuration file is ``/etc/knxd.conf``. ++Socket activation is used for the default IP and Unix sockets ++(port 6720 and /run/knx, respectively). ++ ++Without systemd, on Debian, edit ``/etc/default/knxd``. ++ ++The default Unix socket is ``/run/knx``. ++Old eibd clients may still use ``/tmp/eib`` to talk to knxd. ++You need to either change their configuration, or add "-u /tmp/eib" ++to knxd's options. ++(This was the default for "-u" before version 0.11.) ++ ++ ++### New ".ini" configuration file ++ ++knxd is typically started with "knxd /etc/knxd.ini". ++ ++The file format is documented in "doc/inifile.rst". You might want to use ++the program "/usr/lib/knxd_args" to create it from previous versions' ++command-line arguments. ++ + + ### Adding a TPUART USB interface (serial, USB) + +diff --git a/bootstrap.sh b/bootstrap.sh +index fd3eca7..365058a 100644 +--- a/bootstrap.sh ++++ b/bootstrap.sh +@@ -13,7 +13,7 @@ esac + + # on Debian systems we need pkg-config + if which dpkg >/dev/null && ! which pkg-config >/dev/null ; then +- echo "Package 'pkg-config' missing." ++ echo "Tool 'pkg-config' missing. Install package 'pkgconf' or older 'pkg-config'." + exit 2 + fi + +diff --git a/install-debian.sh b/install-debian.sh +new file mode 100644 +index 0000000..e1432de +--- /dev/null ++++ b/install-debian.sh +@@ -0,0 +1,25 @@ ++#!/bin/sh ++ ++set -ex ++export LC_ALL=C.UTF-8 ++ ++cd "$(dirname "$0")" ++ ++: 1 install tools, minimal variant ++sudo apt-get install --no-install-recommends build-essential devscripts equivs --yes ++ ++: 2 auto-install packages required for building knxd ++sudo mk-build-deps --install --tool='apt-get --no-install-recommends --yes --allow-unauthenticated' debian/control ++rm -f knxd-build-deps_*.deb ../knxd_*.deb ../knxd-tools_*.deb ++ ++: 3 Build. This takes a while. ++dpkg-buildpackage -b -uc ++ ++cd .. ++ ++: 4 Install knxd. Have fun. ++sudo dpkg -i knxd_*.deb knxd-tools_*.deb ++ ++: 5 Clean up. Optional. Remove this if you want to rebuild soon-ish. ++sudo apt remove --autoremove knxd-build-deps --yes ++ diff -Nru knxd-0.14.54.1/debian/patches/series knxd-0.14.69/debian/patches/series --- knxd-0.14.54.1/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/debian/patches/series 2024-12-17 08:40:21.000000000 +0000 @@ -0,0 +1 @@ +dgit-changes diff -Nru knxd-0.14.54.1/debian/rules knxd-0.14.69/debian/rules --- knxd-0.14.54.1/debian/rules 2022-10-25 12:27:52.000000000 +0000 +++ knxd-0.14.69/debian/rules 2024-12-17 08:40:21.000000000 +0000 @@ -3,8 +3,7 @@ # Uncomment this to turn on verbose mode. export DH_VERBOSE=1 -export DEB_BUILD_MAINT_OPTIONS=hardening=-format -export DEB_BUILD_HARDENING_FORMAT=0 +export DEB_BUILD_MAINT_OPTIONS=hardening=+all # This has to be exported to make some magic below work. @@ -19,12 +18,12 @@ rm -f debian/knxd.udev override_dh_auto_configure: configure install-sh - dh_auto_configure -- --enable-usb --enable-groupcache --enable-ft12 --enable-tpuart --enable-dummy --libexecdir=/usr/lib --enable-dependency-tracking --enable-silent-rules + dh_auto_configure -- --enable-usb --enable-groupcache --enable-ft12 --enable-tpuart --enable-dummy --libexecdir=/usr/lib --enable-dependency-tracking configure install-sh: configure.ac sh bootstrap.sh -override_dh_install: debian/knxd.install debian/knxd.socket debian/knxd.service debian/knxd.udev +override_dh_install: debian/knxd.install debian/knxd.socket debian/knxd-net.socket debian/knxd.service debian/knxd.udev dh_install dh_systemd_enable || true dh_systemd_start || true @@ -41,9 +40,11 @@ debian/knxd.socket: systemd/knxd.socket test -e $^ && cp $^ $@ +debian/knxd-net.socket: systemd/knxd-net.socket + test -e $^ && cp $^ $@ debian/knxd.service: systemd/knxd.service test -e $^ && cp $^ $@ -systemd/knxd.socket systemd/knxd.service: +systemd/knxd.socket systemd/knxd-net.socket systemd/knxd.service: $(MAKE) -C systemd override_dh_auto_test: diff -Nru knxd-0.14.54.1/debian/source/format knxd-0.14.69/debian/source/format --- knxd-0.14.54.1/debian/source/format 2022-10-25 12:28:34.000000000 +0000 +++ knxd-0.14.69/debian/source/format 2024-12-17 08:40:21.000000000 +0000 @@ -1 +1 @@ -3.0 (native) +3.0 (quilt) diff -Nru knxd-0.14.54.1/doc/inifile.rst knxd-0.14.69/doc/inifile.rst --- knxd-0.14.54.1/doc/inifile.rst 2021-12-06 10:23:22.000000000 +0000 +++ knxd-0.14.69/doc/inifile.rst 2024-12-16 15:40:26.000000000 +0000 @@ -490,15 +490,16 @@ * nat-ip (string: IP address) - ?? + Target IP address for the tunnelling servers responses and requests. + When set to zero the server shall use the IP address in the IP packet received. - Mandatory if "nat" is set, otherwise disallowed. + Defaults to "0.0.0.0" if "nat" is set, otherwise ignored. * data-port (int) - ?? + Target port number for the tunnelling servers responses and requests. - Mandatory if "nat" is set, otherwise disallowed. + Defaults to 0 if "nat" is set, otherwise ignored. .. Note:: @@ -872,6 +873,60 @@ -S|--Server argument has to be used last and accepted the options mentioned above. +tcptunsrv +---------- + +The "tcptunsrv" server allows clients to connect knxd using the KNXnet/ip +TCP tunneling protocol. + +* tunnel (str) + + This option names a section with configuration for tunnelled + connections. It's OK if that section doesn't exist or is empty. + +* port (int) + + The TCP port to listen on / transmit to. + + Optional; the default is 3671. + +* systemd-ignore (bool) + + Ignore this server when knxd is started via systemd. + + Optional; default "true" if listening on TCP port 3671. + +* heartbeat-timeout (integer: keep-alive timeout) + + The maximum time between status messages from tunnel clients. A client + that doesn't send any packets for this long is disconnected. + +unixtunsrv +---------- + +The "unixtunsrv" server allows clients to connect knxd using the KNXnet/ip +TCP tunneling protocol over Unix domain sockets. + +* tunnel (str) + + This option names a section with configuration for tunnelled + connections. It's OK if that section doesn't exist or is empty. + +* path (string: file name) + + Path to the socket file to use. + +* systemd-ignore (bool) + + Ignore this server when knxd is started via systemd. + + Optional; default is "false" + +* heartbeat-timeout (integer: keep-alive timeout) + + The maximum time between status messages from tunnel clients. A client + that doesn't send any packets for this long is disconnected. + knxd_unix --------- @@ -1092,6 +1147,8 @@ The "queue" filter does not yet have any parameters. +Currently, a queue can grow without bounds; it also does **not** filter +multiple packets to the same group address. pace ---- @@ -1102,25 +1159,25 @@ The delay between transmissions. - Optional. The default is 20 msec. + Optional. The default is 15 msec. * delay-per-byte (float, msec) Additional delay per byte of longer messages, in milliseconds. + Note that protocol headers and other overhead is ignored here. + The fixed-overhead part of the KNX protocol must be factored into the + ``delay`` parameter. + Optional; the default is 1 msec, which roughly corresponds to one byte at 9600 baud (speed of the KNX bus). - Note that the fixed part of the protocol is ignored here: a "short - write" has an additional length delay of zero. The fixed-overhead part - of the KNX protocol should be factored into the per-message delay. - * incoming (float, proportion) - Normally, the "pace" filter only considers outgoing packets. However, + The "pace" filter only considers outgoing packets. However, since KNX is a bus, incoming data also need to be considered. - This parameter controls how much incoming data should contribute to the + This parameter controls whether incoming data should contribute to the filter's delay. Optional. The default is 0.75. @@ -1132,16 +1189,36 @@ *before* checking whether they have free buffer space for more data … Note that knxd schedules packet transmission synchronously. Thus, this -filter acts globally (it delays transmission to *all* interfaces) unless +filter acts globally (it delays sending to *all* interfaces) unless there is a ``queue`` filter in front of it. +If you use this filter to rate-limit a sender by more than the recipient's +data rate, you should set the ``incoming`` parameter to zero. Otherwise a +high rate of incoming messages will block the sender entirely. + +.. Note:: + + If you need this filter for reliable operation on an "ipt" tunnel + interface, this is an indication of sloppy programming on the other + end. A gateway *must not* acknowledge a message which it then + throws away, presumably because its send buffer is full. + + Please file a complaint with the gateway's manufacturer. + monitor ------- This filter forwards all packets passing through it to knxd's bus monitoring system. -TODO. +* recv (bool; ``--arg=recv=BOOL``) + + Monitor incoming packets. Defaults to true. + +* send (bool; ``--arg=send=BOOL``) + + Monitor outgoing packets. Defaults to true. + log --- diff -Nru knxd-0.14.54.1/install-debian.sh knxd-0.14.69/install-debian.sh --- knxd-0.14.54.1/install-debian.sh 2022-10-25 12:27:52.000000000 +0000 +++ knxd-0.14.69/install-debian.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -#!/bin/sh - -set -ex -export LC_ALL=C.UTF-8 - -cd "$(dirname "$0")" - -: 1 install tools, minimal variant -sudo apt-get install --no-install-recommends build-essential devscripts equivs - -: 2 auto-install packages required for building knxd -sudo mk-build-deps --install --tool='apt-get --no-install-recommends --yes --allow-unauthenticated' debian/control -rm -f knxd-build-deps_*.deb - -: 3 Build. Takes a while. -dpkg-buildpackage -b -uc - -cd .. - -: 4 Install knxd. Have fun. -sudo dpkg -i knxd_*.deb knxd-tools_*.deb - -: 5 Clean up. Optional. Remove this if you want to rebuild soon-ish. -sudo apt remove --autoremove knxd-build-deps - diff -Nru knxd-0.14.54.1/m4/ccforbuild.m4 knxd-0.14.69/m4/ccforbuild.m4 --- knxd-0.14.54.1/m4/ccforbuild.m4 2018-04-23 11:45:20.000000000 +0000 +++ knxd-0.14.69/m4/ccforbuild.m4 2024-12-16 15:40:26.000000000 +0000 @@ -69,7 +69,7 @@ int main () { - exit(0); + return 0; } EOF gmp_compile="$1 conftest.c" @@ -143,7 +143,7 @@ int main () { - exit (0); + return 0; } EOF for i in .exe ,ff8 ""; do diff -Nru knxd-0.14.54.1/src/backend/Makefile.am knxd-0.14.69/src/backend/Makefile.am --- knxd-0.14.54.1/src/backend/Makefile.am 2020-03-25 10:46:14.000000000 +0000 +++ knxd-0.14.69/src/backend/Makefile.am 2024-12-16 15:40:26.000000000 +0000 @@ -26,5 +26,11 @@ AM_CPPFLAGS=-I$(top_srcdir)/src/libserver -I$(top_srcdir)/src/common -I$(top_srcdir)/src/usb $(LIBUSB_CFLAGS) libbackend_a_SOURCES= $(FT12) $(TPUART_COMMON) $(EIBNETIP) $(EIBNETIPTUNNEL) \ - log.cpp dummy.cpp nat.cpp fqueue.cpp fpace.cpp + log.cpp \ + dummy.cpp \ + nat.cpp \ + fqueue.cpp \ + fpace.cpp \ + monitor.cpp \ + # end diff -Nru knxd-0.14.54.1/src/backend/eibnetrouter.cpp knxd-0.14.69/src/backend/eibnetrouter.cpp --- knxd-0.14.54.1/src/backend/eibnetrouter.cpp 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/backend/eibnetrouter.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -16,6 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include #include "eibnetrouter.h" @@ -33,7 +34,7 @@ EIBNetIPRouter::start() { struct sockaddr_in baddr; - struct ip_mreq mcfg; + struct ip_mreqn mcfg; TRACEPRINTF (t, 2, "Open"); memset (&baddr, 0, sizeof (baddr)); #ifdef HAVE_SOCKADDR_IN_LEN @@ -62,7 +63,8 @@ sock->localaddr.sin_port = sock->sendaddr.sin_port; mcfg.imr_multiaddr = sock->sendaddr.sin_addr; - mcfg.imr_interface.s_addr = htonl (INADDR_ANY); + mcfg.imr_address.s_addr = htonl (INADDR_ANY); + mcfg.imr_ifindex = if_nametoindex(interface.c_str()); if (!sock->SetMulticast (mcfg)) goto err_out; TRACEPRINTF (t, 2, "Opened"); diff -Nru knxd-0.14.54.1/src/backend/eibnettunnel.cpp knxd-0.14.69/src/backend/eibnettunnel.cpp --- knxd-0.14.54.1/src/backend/eibnettunnel.cpp 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/backend/eibnettunnel.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -74,7 +74,7 @@ monitor = cfg->value("monitor",false); if(NAT) { - srcip = cfg->value("nat-ip",""); + srcip = cfg->value("nat-ip","0.0.0.0"); dataport = cfg->value("data-port",0); } heartbeat_time = cfg->value("heartbeat-timer",30); diff -Nru knxd-0.14.54.1/src/backend/fpace.cpp knxd-0.14.69/src/backend/fpace.cpp --- knxd-0.14.54.1/src/backend/fpace.cpp 2021-01-02 10:22:00.000000000 +0000 +++ knxd-0.14.69/src/backend/fpace.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -19,6 +19,9 @@ #include "fpace.h" +/* add formatter for fmt >= 10.0.0 */ +int format_as(PSTATE t) { return t; } + PaceFilter::PaceFilter (const LinkConnectPtr_& c, IniSectionPtr& s) : Filter(c,s) { last_len=0; @@ -50,7 +53,7 @@ byte_delay = cfg->value("delay-per-byte",1)/1000.; if (byte_delay < 0) { - ERRORPRINTF(t, E_ERROR | 1, "The delay must be >0"); + ERRORPRINTF(t, E_ERROR | 1, "The byte delay must be >=0"); return false; } factor_in = cfg->value("incoming",0.75); diff -Nru knxd-0.14.54.1/src/backend/fqueue.cpp knxd-0.14.69/src/backend/fqueue.cpp --- knxd-0.14.54.1/src/backend/fqueue.cpp 2020-03-18 08:40:46.000000000 +0000 +++ knxd-0.14.69/src/backend/fqueue.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -19,6 +19,9 @@ #include "fqueue.h" +/* add formatter for fmt >= 10.0.0 */ +int format_as(QSTATE t) { return t; } + QueueFilter::QueueFilter (const LinkConnectPtr_& c, IniSectionPtr& s) : Filter(c,s) { trigger.set(this); diff -Nru knxd-0.14.54.1/src/backend/ft12.cpp knxd-0.14.69/src/backend/ft12.cpp --- knxd-0.14.54.1/src/backend/ft12.cpp 2020-05-12 07:21:44.000000000 +0000 +++ knxd-0.14.69/src/backend/ft12.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -115,7 +115,7 @@ if (cfg->value("device","").length() > 0) { if (cfg->value("ip-address","").length() > 0 || - cfg->value("port",-1) != -1) + cfg->value("dest-port",-1) != -1) { ERRORPRINTF (t, E_ERROR | 5, "Don't specify both device and IP options!"); return false; diff -Nru knxd-0.14.54.1/src/backend/monitor.cpp knxd-0.14.69/src/backend/monitor.cpp --- knxd-0.14.54.1/src/backend/monitor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/src/backend/monitor.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -0,0 +1,68 @@ +/* + EIBD eib bus monitor filter + Copyright (C) 2020 MagicBear + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "monitor.h" +#include "cm_tp1.h" + +bool +MonitorL2Filter::setup() +{ + if (!Filter::setup()) + return false; + auto cn = conn.lock(); + if (cn == nullptr) + return false; + mon_send = cfg->value("send",true); + mon_recv = cfg->value("recv",true); + + return true; +} + + +void +MonitorL2Filter::recv_L_Busmonitor (LBusmonPtr l) +{ + Filter::recv_L_Busmonitor(std::move(l)); +} + + +void +MonitorL2Filter::recv_L_Data (LDataPtr l) +{ + if (mon_recv){ + CArray cm_tp1_array = L_Data_to_CM_TP1(l); + LBusmonPtr mon_l = LBusmonPtr(new L_Busmon_PDU ()); + mon_l->lpdu.set (cm_tp1_array); + Filter::recv_L_Busmonitor(std::move(mon_l)); + } + Filter::recv_L_Data(std::move(l)); +} + + +void +MonitorL2Filter::send_L_Data (LDataPtr l) +{ + if (mon_send){ + CArray cm_tp1_array = L_Data_to_CM_TP1(l); + LBusmonPtr mon_l = LBusmonPtr(new L_Busmon_PDU ()); + mon_l->lpdu.set (cm_tp1_array); + Filter::recv_L_Busmonitor(std::move(mon_l)); + } + Filter::send_L_Data(std::move(l)); +} diff -Nru knxd-0.14.54.1/src/backend/monitor.h knxd-0.14.69/src/backend/monitor.h --- knxd-0.14.54.1/src/backend/monitor.h 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/src/backend/monitor.h 2024-12-16 15:40:26.000000000 +0000 @@ -0,0 +1,40 @@ +/* + EIBD eib bus monitor filter + Copyright (C) 2020 MagicBear + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef MONITOR_H +#define MONITOR_H +#include "link.h" + +/** monitor L2 filter, is transparent */ +FILTER(MonitorL2Filter,monitor) +{ + bool mon_send; + bool mon_recv; + +public: + MonitorL2Filter (const LinkConnectPtr_& c, IniSectionPtr& s) : Filter(c,s) {} + virtual ~MonitorL2Filter () = default; + + virtual bool setup(); + virtual void recv_L_Data (LDataPtr l); + virtual void send_L_Data (LDataPtr l); + virtual void recv_L_Busmonitor (LBusmonPtr l); +}; + +#endif diff -Nru knxd-0.14.54.1/src/backend/nat.cpp knxd-0.14.69/src/backend/nat.cpp --- knxd-0.14.54.1/src/backend/nat.cpp 2020-03-06 14:05:31.000000000 +0000 +++ knxd-0.14.69/src/backend/nat.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -40,7 +40,7 @@ // LinkConnect – which happens when you try to apply the filter // globally. The former is exceedingly unlikely, but … if (conn.lock() != nullptr) - ERRORPRINTF(t, E_ERROR | 7, "%s: cannot be used globally"); + ERRORPRINTF(t, E_ERROR | 7, "%s: cannot be used globally", name().c_str()); return false; } addr = dynamic_cast(&c->router)->addr; diff -Nru knxd-0.14.54.1/src/backend/ncn5120.cpp knxd-0.14.69/src/backend/ncn5120.cpp --- knxd-0.14.54.1/src/backend/ncn5120.cpp 2020-03-06 14:05:31.000000000 +0000 +++ knxd-0.14.69/src/backend/ncn5120.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -72,7 +72,8 @@ FDdriver * NCN5120wrap::create_serial(LowLevelIface* parent, IniSectionPtr& s) { - return new NCN5120serial(parent,s); + fd_driver = new NCN5120serial(parent,s); + return fd_driver; } void NCN5120wrap::RecvLPDU (const uint8_t * data, int len) diff -Nru knxd-0.14.54.1/src/backend/tpuart.cpp knxd-0.14.69/src/backend/tpuart.cpp --- knxd-0.14.54.1/src/backend/tpuart.cpp 2021-04-14 11:47:58.000000000 +0000 +++ knxd-0.14.69/src/backend/tpuart.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -31,6 +31,9 @@ #include "log.h" #include "cm_tp1.h" +/* add formatter for fmt >= 10.0.0 */ +int format_as(LPDU_Type t) { return t; } + class TPUARTserial : public LLserial { public: @@ -43,7 +46,7 @@ void termios_settings (struct termios &t1) { t1.c_cflag = CS8 | CLOCAL | CREAD | PARENB; - t1.c_iflag = IGNBRK | INPCK | ISIG; + t1.c_iflag = IGNBRK | ISIG; t1.c_oflag = 0; t1.c_lflag = 0; t1.c_cc[VTIME] = 1; @@ -64,7 +67,8 @@ FDdriver * TPUARTwrap::create_serial(LowLevelIface* parent, IniSectionPtr& s) { - return new TPUARTserial(parent,s); + fd_driver = new TPUARTserial(parent,s); + return fd_driver; } @@ -127,7 +131,7 @@ if (cfg->value("device","").length() > 0) { if (cfg->value("ip-address","").length() > 0 || - cfg->value("port",-1) != -1) + cfg->value("dest-port",-1) != -1) { ERRORPRINTF (t, E_ERROR | 25, "Don't specify both device and IP options!"); return false; @@ -345,7 +349,7 @@ setstate(T_wait); break; case T_wait_keepalive: - if (retry < 3) + if (retry > 2) { setstate(T_in_reset); return; @@ -358,6 +362,37 @@ } } +int +TPUARTwrap::enableInputParityCheck() +{ + struct termios t1; + + if (fd_driver == nullptr) + { + // Not possible and not necessary to enable on TCP connections, so just continue. + return 0; + } + + TRACEPRINTF (t, 8, "Enabling input parity check on fd %d\n", fd_driver->get_fd()); + + if (tcgetattr (fd_driver->get_fd(), &t1)) + { + ERRORPRINTF (t, E_ERROR | 70, "tcgetattr failed: %s", strerror(errno)); + return -1; + } + + t1.c_iflag = t1.c_iflag | INPCK; + + if (tcsetattr (fd_driver->get_fd(), TCSANOW, &t1)) + { + ERRORPRINTF (t, E_ERROR | 70, "tcsetattr failed: %s", strerror(errno)); + return -2; + } + + return 0; +} + + void TPUARTwrap::in_check() { @@ -444,7 +479,9 @@ if (state == T_in_reset) { TRACEPRINTF (t, 8, "RESET_ACK"); - setstate(T_in_setaddr); + if (enableInputParityCheck()>=0) + setstate(T_in_setaddr); + // else time out } else TRACEPRINTF (t, 8, "spurious RESET_ACK"); @@ -614,8 +651,13 @@ case T_wait_keepalive: { + if (state == T_wait_keepalive) + retry++; + else + retry = 1; + uint8_t c = 0x02; - TRACEPRINTF (t, 0, "Send GetState %02X", c); + TRACEPRINTF (t, 0, "Send keepalive GetState %02X", c); LowLevelIface::send_Data(c); timer.start(0.5,0); break; diff -Nru knxd-0.14.54.1/src/backend/tpuart.h knxd-0.14.69/src/backend/tpuart.h --- knxd-0.14.54.1/src/backend/tpuart.h 2020-03-18 08:40:46.000000000 +0000 +++ knxd-0.14.69/src/backend/tpuart.h 2024-12-16 15:40:26.000000000 +0000 @@ -108,7 +108,10 @@ protected: virtual FDdriver * create_serial(LowLevelIface* parent, IniSectionPtr& s); + FDdriver *fd_driver = NULL; +private: + int enableInputParityCheck(); }; #endif diff -Nru knxd-0.14.54.1/src/client/go/Makefile.am knxd-0.14.69/src/client/go/Makefile.am --- knxd-0.14.54.1/src/client/go/Makefile.am 2018-04-23 11:45:20.000000000 +0000 +++ knxd-0.14.69/src/client/go/Makefile.am 2024-12-16 15:40:26.000000000 +0000 @@ -1,11 +1,10 @@ CC = $(CC_FOR_BUILD) -CPPFLAGS = $(CPPFLAGS_FOR_BUILD) -CFLAGS = $(CFLAGS_FOR_BUILD) -LDFLAGS = $(LDFLAGS_FOR_BUILD) LIBS = $(LIBS_FOR_BUILD) EXEEXT = $(EXEEXT_FOR_BUILD) -AM_CPPFLAGS=-I$(top_srcdir)/src/include -I$(top_srcdir)/src/client -I$(top_builddir)/src/client +AM_CPPFLAGS=-I$(top_srcdir)/src/include -I$(top_srcdir)/src/client -I$(top_builddir)/src/client $(CPPFLAGS_FOR_BUILD) +AM_CFLAGS = $(CFLAGS_FOR_BUILD) +AM_LDFLAGS = $(LDFLAGS_FOR_BUILD) EXTRA_DIST = io.inc CLEANFILES = gen.inc EIBConnection.go result.inc diff -Nru knxd-0.14.54.1/src/client/lua/Makefile.am knxd-0.14.69/src/client/lua/Makefile.am --- knxd-0.14.54.1/src/client/lua/Makefile.am 2018-04-23 11:45:20.000000000 +0000 +++ knxd-0.14.69/src/client/lua/Makefile.am 2024-12-16 15:40:26.000000000 +0000 @@ -1,11 +1,10 @@ CC = $(CC_FOR_BUILD) -CPPFLAGS = $(CPPFLAGS_FOR_BUILD) -CFLAGS = $(CFLAGS_FOR_BUILD) -LDFLAGS = $(LDFLAGS_FOR_BUILD) LIBS = $(LIBS_FOR_BUILD) EXEEXT = $(EXEEXT_FOR_BUILD) -AM_CPPFLAGS=-I$(top_srcdir)/src/include -I$(top_srcdir)/src/client -I$(top_builddir)/src/client +AM_CPPFLAGS=-I$(top_srcdir)/src/include -I$(top_srcdir)/src/client -I$(top_builddir)/src/client $(CPPFLAGS_FOR_BUILD) +AM_CFLAGS = $(CFLAGS_FOR_BUILD) +AM_LDFLAGS = $(LDFLAGS_FOR_BUILD) EXTRA_DIST = io.inc CLEANFILES = gen.inc EIBConnection.lua result.inc diff -Nru knxd-0.14.54.1/src/client/pascal/Makefile.am knxd-0.14.69/src/client/pascal/Makefile.am --- knxd-0.14.54.1/src/client/pascal/Makefile.am 2018-04-23 11:45:20.000000000 +0000 +++ knxd-0.14.69/src/client/pascal/Makefile.am 2024-12-16 15:40:26.000000000 +0000 @@ -1,11 +1,10 @@ CC = $(CC_FOR_BUILD) -CPPFLAGS = $(CPPFLAGS_FOR_BUILD) -CFLAGS = $(CFLAGS_FOR_BUILD) -LDFLAGS = $(LDFLAGS_FOR_BUILD) LIBS = $(LIBS_FOR_BUILD) EXEEXT = $(EXEEXT_FOR_BUILD) -AM_CPPFLAGS=-I$(top_srcdir)/src/include -I$(top_srcdir)/src/client -I$(top_builddir)/src/client +AM_CPPFLAGS=-I$(top_srcdir)/src/include -I$(top_srcdir)/src/client -I$(top_builddir)/src/client $(CPPFLAGS_FOR_BUILD) +AM_CFLAGS = $(CFLAGS_FOR_BUILD) +AM_LDFLAGS = $(LDFLAGS_FOR_BUILD) EXTRA_DIST = header1.inc header2.inc body1.inc body2.inc hdef.def CLEANFILES = genh.inc gen.inc result.inc EIBD.pas diff -Nru knxd-0.14.54.1/src/client/python/Makefile.am knxd-0.14.69/src/client/python/Makefile.am --- knxd-0.14.54.1/src/client/python/Makefile.am 2018-04-23 11:45:20.000000000 +0000 +++ knxd-0.14.69/src/client/python/Makefile.am 2024-12-16 15:40:26.000000000 +0000 @@ -1,11 +1,10 @@ CC = $(CC_FOR_BUILD) -CPPFLAGS = $(CPPFLAGS_FOR_BUILD) -CFLAGS = $(CFLAGS_FOR_BUILD) -LDFLAGS = $(LDFLAGS_FOR_BUILD) LIBS = $(LIBS_FOR_BUILD) EXEEXT = $(EXEEXT_FOR_BUILD) -AM_CPPFLAGS=-I$(top_srcdir)/src/include -I$(top_srcdir)/src/client -I$(top_builddir)/src/client +AM_CPPFLAGS=-I$(top_srcdir)/src/include -I$(top_srcdir)/src/client -I$(top_builddir)/src/client $(CPPFLAGS_FOR_BUILD) +AM_CFLAGS = $(CFLAGS_FOR_BUILD) +AM_LDFLAGS = $(LDFLAGS_FOR_BUILD) EXTRA_DIST = io.inc CLEANFILES = gen.inc EIBConnection.py result.inc diff -Nru knxd-0.14.54.1/src/client/ruby/Makefile.am knxd-0.14.69/src/client/ruby/Makefile.am --- knxd-0.14.54.1/src/client/ruby/Makefile.am 2018-04-23 11:45:20.000000000 +0000 +++ knxd-0.14.69/src/client/ruby/Makefile.am 2024-12-16 15:40:26.000000000 +0000 @@ -1,11 +1,10 @@ CC = $(CC_FOR_BUILD) -CPPFLAGS = $(CPPFLAGS_FOR_BUILD) -CFLAGS = $(CFLAGS_FOR_BUILD) -LDFLAGS = $(LDFLAGS_FOR_BUILD) LIBS = $(LIBS_FOR_BUILD) EXEEXT = $(EXEEXT_FOR_BUILD) -AM_CPPFLAGS=-I$(top_srcdir)/src/include -I$(top_srcdir)/src/client -I$(top_builddir)/src/client +AM_CPPFLAGS=-I$(top_srcdir)/src/include -I$(top_srcdir)/src/client -I$(top_builddir)/src/client $(CPPFLAGS_FOR_BUILD) +AM_CFLAGS = $(CFLAGS_FOR_BUILD) +AM_LDFLAGS = $(LDFLAGS_FOR_BUILD) EXTRA_DIST=io.inc footer.inc result.inc CLEANFILES = gen.inc EIBConnection.rb result.inc diff -Nru knxd-0.14.54.1/src/examples/vbusmonitor1time.c knxd-0.14.69/src/examples/vbusmonitor1time.c --- knxd-0.14.54.1/src/examples/vbusmonitor1time.c 2020-03-06 14:05:31.000000000 +0000 +++ knxd-0.14.69/src/examples/vbusmonitor1time.c 2024-12-16 15:40:26.000000000 +0000 @@ -20,13 +20,13 @@ #include "common.h" #include #ifdef HAVE_SYS_TIME_H -#include // for gettimeofday +#include /* for gettimeofday */ #endif int main (int ac, char *ag[]) { -//MM hires-time + /* hires-time */ struct timeval tv; struct tm* ptm; char time_string[40]; @@ -40,7 +40,7 @@ milliseconds = tv.tv_usec / 1000; /* Print the formatted time, in seconds, followed by a decimal point and the milliseconds. */ printf ("%s.%03ld\n", time_string, milliseconds); -//MM end time + /* end time */ uint8_t buf[255]; int len; diff -Nru knxd-0.14.54.1/src/include/eibtypes.h knxd-0.14.69/src/include/eibtypes.h --- knxd-0.14.54.1/src/include/eibtypes.h 2020-03-06 14:05:31.000000000 +0000 +++ knxd-0.14.69/src/include/eibtypes.h 2024-12-16 15:40:26.000000000 +0000 @@ -87,6 +87,6 @@ #define EIB_CACHE_READ_NOWAIT 0x0075 #define EIB_CACHE_LAST_UPDATES 0x0076 #define EIB_CACHE_LAST_UPDATES_2 0x0077 -// like last_updates but 32bit counter +/* like last_updates, but 32bit counter */ #endif diff -Nru knxd-0.14.54.1/src/libserver/Makefile.am knxd-0.14.69/src/libserver/Makefile.am --- knxd-0.14.54.1/src/libserver/Makefile.am 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/libserver/Makefile.am 2024-12-16 15:40:26.000000000 +0000 @@ -42,7 +42,7 @@ endif if HAVE_EIBNETSERVER -EIBNETIP = eibnetserver.cpp eibnetserver.h +EIBNETIP = eibnetserver.cpp eibnetserver.h tcptunserver.cpp tcptunserver.h tunchannel.cpp tunchannel.h else EIBNETIP = endif diff -Nru knxd-0.14.54.1/src/libserver/cemi.cpp knxd-0.14.69/src/libserver/cemi.cpp --- knxd-0.14.54.1/src/libserver/cemi.cpp 2020-03-18 08:40:46.000000000 +0000 +++ knxd-0.14.69/src/libserver/cemi.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -72,6 +72,7 @@ void CEMIDriver::started() { + sent_comm_mode = false; after_reset = true; reset_timer.start(0.5,0); sendReset(); @@ -87,9 +88,32 @@ { if (after_reset) { - after_reset = false; - reset_timer.stop(); - EMI_Common::started(); + if (!sent_comm_mode) + { + sent_comm_mode = true; + + // Set the comm mode to "Data Link Layer" (0x00) + CArray set_comm_mode; + set_comm_mode.resize (8); + set_comm_mode[0] = 0xf6; // Message Code (MC), M_PropWrite.req + // Interface Object Type = cEMI Server Object + set_comm_mode[1] = 0x00; // IOTH + set_comm_mode[2] = 0x08; // IOTL + set_comm_mode[3] = 0x01; // Object Instance (OI) + set_comm_mode[4] = 0x34; // Property ID (PID), PID_COMM_MODE (52) + // number of elements (NoE) = 0x1 + // start index (SIx) = 0x001 + set_comm_mode[5] = 0x10; // NoE, SIx + set_comm_mode[6] = 0x01; // SIx + set_comm_mode[7] = 0x00; // Data (0x00 is "Data Link Layer") + send_Data (set_comm_mode); + } + else + { + after_reset = false; + reset_timer.stop(); + EMI_Common::started(); + } } else EMI_Common::do_send_Next(); diff -Nru knxd-0.14.54.1/src/libserver/cemi.h knxd-0.14.69/src/libserver/cemi.h --- knxd-0.14.54.1/src/libserver/cemi.h 2020-03-17 14:25:13.000000000 +0000 +++ knxd-0.14.69/src/libserver/cemi.h 2024-12-16 15:40:26.000000000 +0000 @@ -59,6 +59,7 @@ void sendLocal_done_cb(bool success); bool after_reset = false; + bool sent_comm_mode = false; ev::timer reset_timer; void reset_timer_cb(ev::timer &w, int revents); diff -Nru knxd-0.14.54.1/src/libserver/client.cpp knxd-0.14.69/src/libserver/client.cpp --- knxd-0.14.54.1/src/libserver/client.cpp 2020-03-18 08:40:46.000000000 +0000 +++ knxd-0.14.69/src/libserver/client.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -35,6 +35,10 @@ #endif #include "server.h" +ClientConnectionBase::~ClientConnectionBase () +{ +} + ClientConnection::ClientConnection (NetServerPtr s, int fd) : router(static_cast(s->router)), sendbuf(fd),recvbuf(fd) { t = TracePtr(new Trace(*(s->t))); diff -Nru knxd-0.14.54.1/src/libserver/client.h knxd-0.14.69/src/libserver/client.h --- knxd-0.14.54.1/src/libserver/client.h 2020-03-18 08:40:46.000000000 +0000 +++ knxd-0.14.69/src/libserver/client.h 2024-12-16 15:40:26.000000000 +0000 @@ -39,12 +39,23 @@ class A__Base; -/** implements a client connection */ -class ClientConnection : public std::enable_shared_from_this +/** a client connection, either for the knxd protocol or for tcp tunnelling */ +class ClientConnectionBase { public: + virtual ~ClientConnectionBase (); + + virtual bool setup() = 0; + virtual void start() = 0; + virtual void stop(bool err) = 0; + bool running = false; +}; +/** implements a knxd protocol client connection */ +class ClientConnection : public ClientConnectionBase, public std::enable_shared_from_this +{ +public: /** Layer 3 interface */ Router &router; /** my address */ diff -Nru knxd-0.14.54.1/src/libserver/cm_ip.cpp knxd-0.14.69/src/libserver/cm_ip.cpp --- knxd-0.14.54.1/src/libserver/cm_ip.cpp 2020-04-05 12:49:03.000000000 +0000 +++ knxd-0.14.69/src/libserver/cm_ip.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -27,12 +27,12 @@ #include CArray -IPtoEIBNetIP (const struct sockaddr_in * a, bool nat) +IPtoEIBNetIP (const struct sockaddr_in * a, bool nat, uint8_t protocol) { CArray buf; buf.resize (8); buf[0] = 0x08; - buf[1] = 0x01; + buf[1] = protocol; if (nat) { buf[2] = 0; @@ -56,11 +56,11 @@ bool EIBnettoIP (const CArray & buf, struct sockaddr_in *a, - const struct sockaddr_in *src, bool & nat) + const struct sockaddr_in *src, bool & nat, uint8_t protocol) { int ip, port; memset (a, 0, sizeof (*a)); - if (buf[0] != 0x8 || buf[1] != 0x1) + if (buf[0] != 0x8 || buf[1] != protocol) return true; ip = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | (buf[5]); port = (buf[6] << 8) | (buf[7]); diff -Nru knxd-0.14.54.1/src/libserver/cm_ip.h knxd-0.14.69/src/libserver/cm_ip.h --- knxd-0.14.54.1/src/libserver/cm_ip.h 2020-03-06 14:05:31.000000000 +0000 +++ knxd-0.14.69/src/libserver/cm_ip.h 2024-12-16 15:40:26.000000000 +0000 @@ -30,11 +30,11 @@ #include "common.h" /** convert a to EIBnet/IP format */ -CArray IPtoEIBNetIP (const struct sockaddr_in *a, bool nat); +CArray IPtoEIBNetIP (const struct sockaddr_in *a, bool nat, uint8_t protocol); /** convert EIBnet/IP IP Address to a */ bool EIBnettoIP (const CArray & buf, struct sockaddr_in *a, - const struct sockaddr_in *src, bool & nat); + const struct sockaddr_in *src, bool & nat, uint8_t protocol); #endif diff -Nru knxd-0.14.54.1/src/libserver/eibnetip.cpp knxd-0.14.69/src/libserver/eibnetip.cpp --- knxd-0.14.54.1/src/libserver/eibnetip.cpp 2020-04-05 12:49:03.000000000 +0000 +++ knxd-0.14.69/src/libserver/eibnetip.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -34,7 +34,7 @@ } EIBNetIPPacket * -EIBNetIPPacket::fromPacket (const CArray & c, const struct sockaddr_in src) +EIBNetIPPacket::fromPacket (const CArray & c, const struct sockaddr_in src, HostProtocolCode protocol) { EIBNetIPPacket *p; if (c.size() < 6) @@ -48,6 +48,7 @@ p->service = (c[2] << 8) | c[3]; p->data.set (c.data() + 6, len - 6); p->src = src; + p->protocol = protocol; return p; } @@ -199,7 +200,7 @@ } bool -EIBNetIPSocket::SetMulticast (struct ip_mreq multicastaddr) +EIBNetIPSocket::SetMulticast (struct ip_mreqn multicastaddr) { if (multicast) return false; @@ -311,12 +312,12 @@ memset (&caddr, 0, sizeof (caddr)); } -EIBNetIPPacket EIBnet_SearchRequest::ToPacket ()const +EIBNetIPPacket EIBnet_SearchRequest::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; CArray - ca = IPtoEIBNetIP (&caddr, nat); + ca = IPtoEIBNetIP (&caddr, nat, protocol); p.service = SEARCH_REQUEST; p.data = ca; return p; @@ -329,7 +330,7 @@ return 1; if (p.data.size() != 8) return 1; - if (EIBnettoIP (p.data, &r.caddr, &p.src, r.nat)) + if (EIBnettoIP (p.data, &r.caddr, &p.src, r.nat, p.protocol)) return 1; return 0; } @@ -343,10 +344,10 @@ memset (&name, 0, sizeof (name)); } -EIBNetIPPacket EIBnet_SearchResponse::ToPacket ()const +EIBNetIPPacket EIBnet_SearchResponse::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; - CArray ca = IPtoEIBNetIP (&caddr, nat); + CArray ca = IPtoEIBNetIP (&caddr, nat, protocol); p.service = SEARCH_RESPONSE; p.data.resize (64 + services.size() * 2); p.data.setpart (ca, 0); @@ -381,7 +382,7 @@ return 1; if (p.data.size() < 64) return 1; - if (EIBnettoIP (CArray (p.data.data() + 0, 8), &r.caddr, &p.src, r.nat)) + if (EIBnettoIP (CArray (p.data.data() + 0, 8), &r.caddr, &p.src, r.nat, p.protocol)) return 1; if (p.data[8] != 54) return 1; @@ -416,12 +417,12 @@ memset (&caddr, 0, sizeof (caddr)); } -EIBNetIPPacket EIBnet_DescriptionRequest::ToPacket ()const +EIBNetIPPacket EIBnet_DescriptionRequest::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; CArray - ca = IPtoEIBNetIP (&caddr, nat); + ca = IPtoEIBNetIP (&caddr, nat, protocol); p.service = DESCRIPTION_REQUEST; p.data = ca; return p; @@ -435,7 +436,7 @@ return 1; if (p.data.size() != 8) return 1; - if (EIBnettoIP (p.data, &r.caddr, &p.src, r.nat)) + if (EIBnettoIP (p.data, &r.caddr, &p.src, r.nat, p.protocol)) return 1; return 0; } @@ -448,7 +449,7 @@ memset (&name, 0, sizeof (name)); } -EIBNetIPPacket EIBnet_DescriptionResponse::ToPacket ()const +EIBNetIPPacket EIBnet_DescriptionResponse::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; @@ -522,12 +523,12 @@ memset (&daddr, 0, sizeof (daddr)); } -EIBNetIPPacket EIBnet_ConnectRequest::ToPacket ()const +EIBNetIPPacket EIBnet_ConnectRequest::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; CArray ca, da; - ca = IPtoEIBNetIP (&caddr, nat); - da = IPtoEIBNetIP (&daddr, nat); + ca = IPtoEIBNetIP (&caddr, nat, protocol); + da = IPtoEIBNetIP (&daddr, nat, protocol); p.service = CONNECTION_REQUEST; p.data.resize (ca.size() + da.size() + 1 + CRI.size()); p.data.setpart (ca, 0); @@ -545,9 +546,9 @@ return 1; if (p.data.size() < 18) return 1; - if (EIBnettoIP (CArray (p.data.data(), 8), &r.caddr, &p.src, r.nat)) + if (EIBnettoIP (CArray (p.data.data(), 8), &r.caddr, &p.src, r.nat, p.protocol)) return 1; - if (EIBnettoIP (CArray (p.data.data() + 8, 8), &r.daddr, &p.src, r.nat)) + if (EIBnettoIP (CArray (p.data.data() + 8, 8), &r.daddr, &p.src, r.nat, p.protocol)) return 1; if (p.data.size() - 16 != p.data[16]) return 1; @@ -560,10 +561,10 @@ memset (&daddr, 0, sizeof (daddr)); } -EIBNetIPPacket EIBnet_ConnectResponse::ToPacket ()const +EIBNetIPPacket EIBnet_ConnectResponse::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; - CArray da = IPtoEIBNetIP (&daddr, nat); + CArray da = IPtoEIBNetIP (&daddr, nat, protocol); p.service = CONNECTION_RESPONSE; if (status != 0) p.data.resize (2); @@ -598,7 +599,7 @@ } if (p.data.size() < 12) return 1; - if (EIBnettoIP (CArray (p.data.data() + 2, 8), &r.daddr, &p.src, r.nat)) + if (EIBnettoIP (CArray (p.data.data() + 2, 8), &r.daddr, &p.src, r.nat, p.protocol)) return 1; if (p.data.size() - 10 != p.data[10]) return 1; @@ -613,10 +614,10 @@ memset (&caddr, 0, sizeof (caddr)); } -EIBNetIPPacket EIBnet_ConnectionStateRequest::ToPacket ()const +EIBNetIPPacket EIBnet_ConnectionStateRequest::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; - CArray ca = IPtoEIBNetIP (&caddr, nat); + CArray ca = IPtoEIBNetIP (&caddr, nat, protocol); p.service = CONNECTIONSTATE_REQUEST; p.data.resize (ca.size() + 2); p.data[0] = channel; @@ -633,13 +634,13 @@ return 1; if (p.data.size() != 10) return 1; - if (EIBnettoIP (CArray (p.data.data() + 2, 8), &r.caddr, &p.src, r.nat)) + if (EIBnettoIP (CArray (p.data.data() + 2, 8), &r.caddr, &p.src, r.nat, p.protocol)) return 1; r.channel = p.data[0]; return 0; } -EIBNetIPPacket EIBnet_ConnectionStateResponse::ToPacket ()const +EIBNetIPPacket EIBnet_ConnectionStateResponse::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; p.service = CONNECTIONSTATE_RESPONSE; @@ -667,10 +668,10 @@ memset (&caddr, 0, sizeof (caddr)); } -EIBNetIPPacket EIBnet_DisconnectRequest::ToPacket ()const +EIBNetIPPacket EIBnet_DisconnectRequest::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; - CArray ca = IPtoEIBNetIP (&caddr, nat); + CArray ca = IPtoEIBNetIP (&caddr, nat, protocol); p.service = DISCONNECT_REQUEST; p.data.resize (ca.size() + 2); p.data[0] = channel; @@ -687,13 +688,13 @@ return 1; if (p.data.size() != 10) return 1; - if (EIBnettoIP (CArray (p.data.data() + 2, 8), &r.caddr, &p.src, r.nat)) + if (EIBnettoIP (CArray (p.data.data() + 2, 8), &r.caddr, &p.src, r.nat, p.protocol)) return 1; r.channel = p.data[0]; return 0; } -EIBNetIPPacket EIBnet_DisconnectResponse::ToPacket ()const +EIBNetIPPacket EIBnet_DisconnectResponse::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; p.service = DISCONNECT_RESPONSE; @@ -716,7 +717,7 @@ return 0; } -EIBNetIPPacket EIBnet_ConfigRequest::ToPacket ()const +EIBNetIPPacket EIBnet_ConfigRequest::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; p.service = DEVICE_CONFIGURATION_REQUEST; @@ -744,7 +745,7 @@ return 0; } -EIBNetIPPacket EIBnet_ConfigACK::ToPacket ()const +EIBNetIPPacket EIBnet_ConfigACK::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; p.service = DEVICE_CONFIGURATION_ACK; @@ -771,7 +772,7 @@ return 0; } -EIBNetIPPacket EIBnet_TunnelRequest::ToPacket ()const +EIBNetIPPacket EIBnet_TunnelRequest::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; p.service = TUNNEL_REQUEST; @@ -799,7 +800,7 @@ return 0; } -EIBNetIPPacket EIBnet_TunnelACK::ToPacket ()const +EIBNetIPPacket EIBnet_TunnelACK::ToPacket (HostProtocolCode protocol)const { EIBNetIPPacket p; p.service = TUNNEL_RESPONSE; @@ -826,7 +827,7 @@ return 0; } -EIBNetIPPacket EIBnet_RoutingIndication::ToPacket () const +EIBNetIPPacket EIBnet_RoutingIndication::ToPacket (HostProtocolCode protocol) const { // @todo abort(); @@ -838,7 +839,7 @@ return 0; } -EIBNetIPPacket EIBnet_RoutingLostMessage::ToPacket () const +EIBNetIPPacket EIBnet_RoutingLostMessage::ToPacket (HostProtocolCode protocol) const { // @todo abort(); diff -Nru knxd-0.14.54.1/src/libserver/eibnetip.h knxd-0.14.69/src/libserver/eibnetip.h --- knxd-0.14.54.1/src/libserver/eibnetip.h 2020-03-18 08:40:46.000000000 +0000 +++ knxd-0.14.69/src/libserver/eibnetip.h 2024-12-16 15:40:26.000000000 +0000 @@ -39,6 +39,9 @@ // all values are from 03_08_01 5.* unless otherwise specified +#define KNXNETIP_VERSION_10 0x10 +#define HEADER_SIZE_10 0x06 + /** Service type identifiers */ enum ServiceType : uint16_t { @@ -129,6 +132,14 @@ IPV4_TCP = 0x02, }; +/** Tunnelling KNX layers */ +enum TunnellingLayer : uint8_t +{ + TUNNEL_LINKLAYER = 0x02, + TUNNEL_RAW = 0x04, + TUNNEL_BUSMONITOR = 0x80, +}; + /* Timeout constants */ constexpr ev::tstamp CONNECT_REQUEST_TIMEOUT = 10; constexpr ev::tstamp CONNECTIONSTATE_REQUEST_TIMEOUT = 10; @@ -148,6 +159,15 @@ uint8_t version; }; +// A sockaddr_in for "Route Back" HPAIs +// See ISO 22510:2019 section 5.2.8.6.2 b) +inline sockaddr_in routeBackAddr() +{ + sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + return addr; +} + /** represents a EIBnet/IP packet */ class EIBNetIPPacket { @@ -156,6 +176,8 @@ int service; /** payload */ CArray data; + /** the protocol over which the packet is transported */ + HostProtocolCode protocol; /** source address */ struct sockaddr_in src; @@ -164,7 +186,8 @@ /** create from character array */ static EIBNetIPPacket *fromPacket (const CArray & c, - const struct sockaddr_in src); + const struct sockaddr_in src, + HostProtocolCode protocol = IPV4_UDP); /** convert to character array */ CArray ToPacket () const; }; @@ -175,7 +198,7 @@ EIBnet_SearchRequest (); struct sockaddr_in caddr; bool nat = false; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_SearchRequest (const EIBNetIPPacket & p, @@ -196,7 +219,7 @@ char name[30]; struct sockaddr_in caddr; bool nat = false; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_SearchResponse (const EIBNetIPPacket & p, @@ -208,7 +231,7 @@ EIBnet_DescriptionRequest (); struct sockaddr_in caddr; bool nat = false; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_DescriptionRequest (const EIBNetIPPacket & p, @@ -228,7 +251,7 @@ uint8_t MAC[6]; char name[30]; CArray optional; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_DescriptionResponse (const EIBNetIPPacket & p, @@ -242,7 +265,7 @@ struct sockaddr_in daddr; CArray CRI; bool nat = false; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_ConnectRequest (const EIBNetIPPacket & p, @@ -257,7 +280,7 @@ struct sockaddr_in daddr; bool nat = false; CArray CRD; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_ConnectResponse (const EIBNetIPPacket & p, @@ -271,7 +294,7 @@ uint8_t status = 0; struct sockaddr_in caddr; bool nat = false; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_ConnectionStateRequest (const EIBNetIPPacket & p, @@ -283,7 +306,7 @@ EIBnet_ConnectionStateResponse () = default; uint8_t channel = 0; uint8_t status = 0; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_ConnectionStateResponse (const EIBNetIPPacket & p, @@ -296,7 +319,7 @@ struct sockaddr_in caddr; uint8_t channel = 0; bool nat = false; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_DisconnectRequest (const EIBNetIPPacket & p, @@ -308,7 +331,7 @@ EIBnet_DisconnectResponse () = default; uint8_t channel = 0; uint8_t status = 0; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_DisconnectResponse (const EIBNetIPPacket & p, @@ -321,7 +344,7 @@ uint8_t channel = 0; uint8_t seqno = 0; CArray CEMI; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_ConfigRequest (const EIBNetIPPacket & p, @@ -334,7 +357,7 @@ uint8_t channel = 0; uint8_t seqno = 0; uint8_t status = 0; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_ConfigACK (const EIBNetIPPacket & p, EIBnet_ConfigACK & r); // @todo rename to parseEIBnet_DeviceConfigurationAck @@ -346,7 +369,7 @@ uint8_t channel = 0; uint8_t seqno = 0; CArray CEMI; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_TunnelRequest (const EIBNetIPPacket & p, @@ -359,21 +382,21 @@ uint8_t channel = 0; uint8_t seqno = 0; uint8_t status = 0; - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_TunnelACK (const EIBNetIPPacket & p, EIBnet_TunnelACK & r); class EIBnet_RoutingIndication { - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_RoutingIndication (const EIBNetIPPacket & p, EIBnet_RoutingIndication & r); class EIBnet_RoutingLostMessage { - EIBNetIPPacket ToPacket () const; + EIBNetIPPacket ToPacket (HostProtocolCode protocol = IPV4_UDP) const; }; int parseEIBnet_RoutingLostMessage (const EIBNetIPPacket & p, EIBnet_RoutingLostMessage & r); @@ -449,7 +472,7 @@ void stop(bool err); /** enables multicast */ - bool SetMulticast (struct ip_mreq multicastaddr); + bool SetMulticast (struct ip_mreqn multicastaddr); /** sends a packet */ void Send (EIBNetIPPacket p, struct sockaddr_in addr); void Send (EIBNetIPPacket p) @@ -507,7 +530,7 @@ void send_q_drop(); /** multicast address */ - struct ip_mreq maddr; + struct ip_mreqn maddr; /** file descriptor */ int fd; /** multicast in use? */ diff -Nru knxd-0.14.54.1/src/libserver/eibnetserver.cpp knxd-0.14.69/src/libserver/eibnetserver.cpp --- knxd-0.14.54.1/src/libserver/eibnetserver.cpp 2022-01-03 12:20:10.000000000 +0000 +++ knxd-0.14.69/src/libserver/eibnetserver.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -57,7 +57,7 @@ : SubDriver(c) { struct sockaddr_in baddr; - struct ip_mreq mcfg; + struct ip_mreqn mcfg; sock = 0; t->setAuxName("driver"); @@ -96,7 +96,8 @@ } mcfg.imr_multiaddr = maddr.sin_addr; - mcfg.imr_interface.s_addr = htonl (INADDR_ANY); + mcfg.imr_address.s_addr = htonl (INADDR_ANY); + mcfg.imr_ifindex = if_nametoindex(intf.c_str()); if (!sock->SetMulticast (mcfg)) goto err_out; @@ -320,7 +321,7 @@ id++; goto rt; } - if (id <= 0xff) + if (id <= 0xff) // TODO configurable maximum { LinkConnectClientPtr conn = LinkConnectClientPtr(new LinkConnectClient(std::dynamic_pointer_cast(shared_from_this()), tunnel_cfg, t)); ConnStatePtr s = ConnStatePtr(new ConnState(this, conn, addr)); @@ -339,8 +340,9 @@ if(!static_cast(router).registerLink(conn, true)) return -1; connections.push_back(s); + return id; } - return id; + return -1; } ConnState::ConnState (EIBnetServer *parent, LinkConnectClientPtr c, eibaddr_t addr) @@ -560,12 +562,10 @@ r2.individual_addr = dynamic_cast(&router)->addr; r2.installid = 0; r2.multicastaddr = mcast->maddr.sin_addr; - r2.serial[0]=1; - r2.serial[1]=2; - r2.serial[2]=3; - r2.serial[3]=4; - r2.serial[4]=5; - r2.serial[5]=6; + // Serial must be deterministic and should consider multiple instances on a system. + std::copy(mac_address, mac_address + sizeof(mac_address), r2.serial.begin()); + r2.serial[0] ^= (Port >> 8) & 0xff; + r2.serial[1] ^= Port & 0xff; //FIXME: Hostname, MAC-addr memcpy(r2.MAC, mac_address, sizeof(r2.MAC)); //FIXME: Hostname, indiv. address @@ -716,7 +716,7 @@ else if (r1.CRI[1] == 0x02 || r1.CRI[1] == 0x80) { int id = addClient ((r1.CRI[1] == 0x80) ? CT_BUSMONITOR : CT_STANDARD, r1, a); - if (id <= 0xff) + if (id >= 0) { r2.channel = id; r2.status = E_NO_ERROR; @@ -734,7 +734,7 @@ r2.CRD[0] = 0x03; TRACEPRINTF (t, 8, "Tunnel CONNECTION_REQ, no addr (mgmt)"); int id = addClient (CT_CONFIG, r1, 0); - if (id <= 0xff) + if (id >= 0) { r2.channel = id; r2.status = E_NO_ERROR; @@ -935,14 +935,14 @@ if (c) { r2.status = 0; + if (c->source_address == 0) + c->source_address = addr; if (r1.CEMI[0] == 0x11) { out.put (L_Data_ToCEMI (0x2E, c)); if (! retries) send_trigger.send(); } - if (c->source_address == 0) - c->source_address = addr; if (r1.CEMI[0] == 0x11 || r1.CEMI[0] == 0x29) recv_L_Data (std::move(c)); else diff -Nru knxd-0.14.54.1/src/libserver/eibnetserver.h knxd-0.14.69/src/libserver/eibnetserver.h --- knxd-0.14.54.1/src/libserver/eibnetserver.h 2022-01-03 12:20:10.000000000 +0000 +++ knxd-0.14.69/src/libserver/eibnetserver.h 2024-12-16 15:40:26.000000000 +0000 @@ -50,6 +50,9 @@ CT_CONFIG, }; +/* add formatter for fmt >= 10.0.0 */ +inline int format_as(ConnType t) { return t; } + /** Driver for tunnels */ class ConnState: public SubDriver, public L_Busmonitor_CallBack { diff -Nru knxd-0.14.54.1/src/libserver/eibusb.cpp knxd-0.14.69/src/libserver/eibusb.cpp --- knxd-0.14.54.1/src/libserver/eibusb.cpp 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/libserver/eibusb.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -24,6 +24,9 @@ #include "emi2.h" #include "usblowlevel.h" +/* add formatter for fmt >= 10.0.0 */ +int format_as(EMIVer t) { return t; } + USBConverterInterface::USBConverterInterface (LowLevelIface * p, IniSectionPtr& s) : LowLevelFilter(p,s) { diff -Nru knxd-0.14.54.1/src/libserver/emi1.cpp knxd-0.14.69/src/libserver/emi1.cpp --- knxd-0.14.54.1/src/libserver/emi1.cpp 2020-03-18 08:40:46.000000000 +0000 +++ knxd-0.14.69/src/libserver/emi1.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -70,7 +70,7 @@ { sendLocal_done_next = N_open; const uint8_t ta[] = { 0x46, 0x01, 0x01, 0x16, 0x00 }; // clear addr tab - send_Local (CArray (ta, sizeof (t)),1); + send_Local (CArray (ta, sizeof (ta)),1); } void diff -Nru knxd-0.14.54.1/src/libserver/emi_common.cpp knxd-0.14.69/src/libserver/emi_common.cpp --- knxd-0.14.54.1/src/libserver/emi_common.cpp 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/libserver/emi_common.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -21,6 +21,9 @@ #include "emi.h" +/* add formatter for fmt >= 10.0.0 */ +int format_as(E_state t) { return t; } + EMIVer cfgEMIVersion(IniSectionPtr& s) { diff -Nru knxd-0.14.54.1/src/libserver/lowlevel.cpp knxd-0.14.69/src/libserver/lowlevel.cpp --- knxd-0.14.54.1/src/libserver/lowlevel.cpp 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/libserver/lowlevel.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -233,3 +233,7 @@ return true; } +int FDdriver::get_fd() +{ + return fd; +} diff -Nru knxd-0.14.54.1/src/libserver/lowlevel.h knxd-0.14.69/src/libserver/lowlevel.h --- knxd-0.14.54.1/src/libserver/lowlevel.h 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/libserver/lowlevel.h 2024-12-16 15:40:26.000000000 +0000 @@ -281,6 +281,7 @@ bool setup(); void start(); void stop(bool err); + int get_fd(); protected: /** device connection */ diff -Nru knxd-0.14.54.1/src/libserver/lpdu.h knxd-0.14.69/src/libserver/lpdu.h --- knxd-0.14.54.1/src/libserver/lpdu.h 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/libserver/lpdu.h 2024-12-16 15:40:26.000000000 +0000 @@ -35,8 +35,8 @@ enum EIB_Priority : uint8_t { PRIO_SYSTEM = 0, - PRIO_URGENT = 1, - PRIO_NORMAL = 2, + PRIO_NORMAL = 1, + PRIO_URGENT = 2, PRIO_LOW = 3 }; diff -Nru knxd-0.14.54.1/src/libserver/retry.cpp knxd-0.14.69/src/libserver/retry.cpp --- knxd-0.14.54.1/src/libserver/retry.cpp 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/libserver/retry.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -19,6 +19,9 @@ #include "retry.h" +/* add formatter for fmt >= 10.0.0 */ +int format_as(RSTATE t) { return t; } + RetryFilter::RetryFilter (const LinkConnectPtr_& c, IniSectionPtr& s) : Filter(c,s) { trigger.set(this); @@ -224,6 +227,14 @@ Filter::stopped(err); } +bool +RetryFilter::hasAddress (eibaddr_t addr) const +{ + if (state != R_UP) + return false; + return Filter::hasAddress(addr); +} + void RetryFilter::trigger_cb (ev::async &, int) { diff -Nru knxd-0.14.54.1/src/libserver/retry.h knxd-0.14.69/src/libserver/retry.h --- knxd-0.14.54.1/src/libserver/retry.h 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/libserver/retry.h 2024-12-16 15:40:26.000000000 +0000 @@ -84,6 +84,7 @@ virtual void started(); virtual void stopped(bool err); + virtual bool hasAddress (eibaddr_t addr) const; }; diff -Nru knxd-0.14.54.1/src/libserver/router.cpp knxd-0.14.69/src/libserver/router.cpp --- knxd-0.14.54.1/src/libserver/router.cpp 2020-03-27 07:28:30.000000000 +0000 +++ knxd-0.14.69/src/libserver/router.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -37,6 +37,7 @@ #include "lowlevel.h" #include "server.h" #include "systemdserver.h" +#include "tcptunserver.h" /** global filter adapter, sending end */ class RouterHigh : public Driver @@ -235,21 +236,56 @@ #ifdef HAVE_SYSTEMD { - std::string sd_name = s->value("systemd",""); - if (sd_name.size() > 0) + std::string sd_name_knxd = s->value("systemd",""); + std::string sd_name_tun = s->value("systemd_tcptunsrv",""); + if (sd_name_knxd.size() > 0 || sd_name_tun.size() > 0) { // IniSectionPtr sd = ini[sd_name]; - (void) ini[sd_name]; // set the section's "referenced" bit, for error checking - int num_fds = sd_listen_fds(0); + // set the section's "referenced" bit, for error checking + if (sd_name_knxd.size() > 0) + (void) ini[sd_name_knxd]; + if (sd_name_tun.size() > 0) + (void) ini[sd_name_tun]; + + char** fd_names_c = nullptr; + int num_fds = sd_listen_fds_with_names(0, &fd_names_c); if( num_fds < 0 ) { ERRORPRINTF (t, E_ERROR | 85, "Error getting fds from systemd."); goto ex; } + std::vector fd_names; + if (fd_names_c) + { + for (char** name = fd_names_c; *name; name++) + { + fd_names.push_back(*name); + free(*name); + } + free(fd_names_c); + } + if (fd_names.size() < num_fds) + { + ERRORPRINTF (t, E_ERROR | 147, "Got too few fds names from systemd."); + goto ex; + } + // zero FDs from systemd is not a bug for( int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START+num_fds; ++fd ) { + std::string name = fd_names[fd - SD_LISTEN_FDS_START]; + TRACEPRINTF (t, 4, "Got fd %d with name '%s'", fd, name); + std::string sd_name; + bool is_tun; + if (name == "knxnet") { + sd_name = sd_name_tun; + is_tun = true; + } else { + sd_name = sd_name_knxd; + is_tun = false; + } + IniSectionPtr sds = ini.add_auto(sd_name); (*sds)["use"] = sd_name; @@ -259,10 +295,16 @@ goto ex; } - ServerPtr sdp = ServerPtr(new SystemdServer(*this, sds, fd)); + ServerPtr sdp; + if (is_tun) { + sdp = ServerPtr(new TcpTunSystemdServer(*this, sds, fd)); + } else { + sdp = ServerPtr(new SystemdServer(*this, sds, fd)); + } if (!sdp->setup()) goto ex; registerLink(sdp); + using_systemd = true; } } diff -Nru knxd-0.14.54.1/src/libserver/server.cpp knxd-0.14.69/src/libserver/server.cpp --- knxd-0.14.54.1/src/libserver/server.cpp 2020-03-18 08:40:46.000000000 +0000 +++ knxd-0.14.69/src/libserver/server.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -28,7 +28,7 @@ #include "client.h" void -NetServer::stop_(bool err) +NetServerBase::stop_(bool err) { TRACEPRINTF (t, 8, "StopServer"); @@ -49,31 +49,31 @@ } void -NetServer::stop(bool err) +NetServerBase::stop(bool err) { stop_(err); stopped(err); } -NetServer::~NetServer () +NetServerBase::~NetServerBase () { // stopped() may not be called from a destructor stop_(false); } void -NetServer::deregister (ClientConnPtr con) +NetServerBase::deregister (ClientConnBasePtr con) { cleanup_q.push(con); cleanup.send(); } void -NetServer::cleanup_cb (ev::async &, int) +NetServerBase::cleanup_cb (ev::async &, int) { while (!cleanup_q.empty()) { - ClientConnPtr con = cleanup_q.get(); + ClientConnBasePtr con = cleanup_q.get(); ITER(i, connections) if (*i == con) @@ -84,14 +84,14 @@ } } -NetServer::NetServer (BaseRouter& r, IniSectionPtr& s) : Server (r,s) +NetServerBase::NetServerBase (BaseRouter& r, IniSectionPtr& s) : Server (r,s) { t->setAuxName("NetServ"); fd = -1; } void -NetServer::start() +NetServerBase::start() { if (fd == -1) { @@ -99,16 +99,16 @@ return; } set_non_blocking(fd); - io.set(this); + io.set(this); io.start(fd,ev::READ); - cleanup.set(this); + cleanup.set(this); cleanup.start(); started(); } void -NetServer::io_cb (ev::io &, int) +NetServerBase::io_cb (ev::io &, int) { int cfd; cfd = accept (fd, NULL,NULL); @@ -116,7 +116,9 @@ { TRACEPRINTF (t, 8, "New Connection"); setupConnection (cfd); - ClientConnPtr c = std::shared_ptr(new ClientConnection (std::static_pointer_cast(shared_from_this()), cfd)); + ClientConnBasePtr c = createConnection(cfd); + if (!c) + return; if (!c->setup()) return; c->start(); @@ -128,7 +130,7 @@ } bool -NetServer::setup() +NetServerBase::setup() { if (!Server::setup()) return false; @@ -140,7 +142,21 @@ } void -NetServer::setupConnection (int) +NetServerBase::setupConnection (int) { ignore_when_systemd = cfg->value("systemd-ignore",ignore_when_systemd); } + +NetServer::NetServer (BaseRouter& r, IniSectionPtr& s) : NetServerBase (r,s) +{ +} + +NetServer::~NetServer () +{ +} + +ClientConnBasePtr +NetServer::createConnection(int cfd) +{ + return std::shared_ptr(new ClientConnection (std::static_pointer_cast(shared_from_this()), cfd)); +} diff -Nru knxd-0.14.54.1/src/libserver/server.h knxd-0.14.69/src/libserver/server.h --- knxd-0.14.54.1/src/libserver/server.h 2020-03-18 08:40:46.000000000 +0000 +++ knxd-0.14.69/src/libserver/server.h 2024-12-16 15:40:26.000000000 +0000 @@ -30,24 +30,26 @@ #include "link.h" #include "router.h" -class ClientConnection; -using ClientConnPtr = std::shared_ptr; +class ClientConnectionBase; +using ClientConnBasePtr = std::shared_ptr; /** implements the frontend (but opens no connection) */ -class NetServer: public Server +class NetServerBase: public Server { friend class ClientConnection; public: - virtual ~NetServer (); + virtual ~NetServerBase (); bool ignore_when_systemd = false; protected: - NetServer (BaseRouter& l3, IniSectionPtr& s); + NetServerBase (BaseRouter& l3, IniSectionPtr& s); /** server socket */ int fd; + virtual ClientConnBasePtr createConnection (int cfd) = 0; + virtual void setupConnection (int cfd); bool setup(); @@ -55,23 +57,32 @@ void stop(bool err); /** deregister client connection */ - void deregister (ClientConnPtr con); + void deregister (ClientConnBasePtr con); private: ev::io io; void io_cb (ev::io &w, int revents); /** open client connections*/ - std::vector < ClientConnPtr > connections; + std::vector < ClientConnBasePtr > connections; ev::async cleanup; void cleanup_cb (ev::async &w, int revents); /** to-be-closed client connections*/ - Queue < ClientConnPtr > cleanup_q; + Queue < ClientConnBasePtr > cleanup_q; void stop_(bool err); }; +class NetServer: public NetServerBase +{ +protected: + NetServer (BaseRouter& l3, IniSectionPtr& s); + virtual ~NetServer (); + + ClientConnBasePtr createConnection(int cfd); +}; + using NetServerPtr = std::shared_ptr; #endif diff -Nru knxd-0.14.54.1/src/libserver/tcptunserver.cpp knxd-0.14.69/src/libserver/tcptunserver.cpp --- knxd-0.14.54.1/src/libserver/tcptunserver.cpp 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/src/libserver/tcptunserver.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -0,0 +1,776 @@ +/* + EIBD eib bus access and management daemon + Copyright (C) 2005-2011 Martin Koegler + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "tcptunserver.h" +#include "config.h" +#include "tunchannel.h" + +#include +#include +#include +#include + +TcpTunConn::TcpTunConn(TcpTunServerBase *parent, uint32_t connectionID, int fd) + : t(TracePtr(new Trace(*parent->t))) + , sendbuf(fd) + , recvbuf(fd) + , connectionID(connectionID) + , fd(fd) +{ + this->parent = parent; + + recvbuf.on_read.set(this); + recvbuf.on_error.set(this); + sendbuf.on_error.set(this); + + timeout.set(this); + timeout.start(parent->keepalive, 0); + + // Get address of local host + sockaddr_in localSocketAddress; + socklen_t len = sizeof(localSocketAddress); + if (getsockname(fd, (struct sockaddr *)&localSocketAddress, &len) != 0 || + len != sizeof(localSocketAddress) || + localSocketAddress.sin_family != AF_INET) + { + char str[64]; + snprintf(str, sizeof(str), "stream-%u", connectionID); + t->setAuxName(str); + } + else + { + char addrStr[INET_ADDRSTRLEN]; + if (inet_ntop(localSocketAddress.sin_family, &localSocketAddress.sin_addr, addrStr, sizeof(addrStr))) + { + char addrPortStr[INET_ADDRSTRLEN + 6]; + snprintf(addrPortStr, sizeof(addrPortStr), "%s:%hu", addrStr, localSocketAddress.sin_port); + t->setAuxName(addrPortStr); + } + else + { + t->setAuxName("addr-error"); + } + } +} + +TcpTunConn::~TcpTunConn() +{ + TRACEPRINTF (t, 8, "Closing TcpTunConn"); +} + +void TcpTunConn::reset_timer() +{ + timeout.set(parent->keepalive, 0); +} + +void +TcpTunConn::error_cb() +{ + TRACEPRINTF (t, 8, "TcpTunConn communication error"); + stop(true); +} + +size_t +TcpTunConn::read_cb(uint8_t *buf, size_t len) +{ + size_t done = 0; + for (;;) { + if (len < HEADER_SIZE_10) + return done; + if (buf[0] != HEADER_SIZE_10 || buf[1] != KNXNETIP_VERSION_10) + { + stop(true); + return done; + } + int tlen = (buf[4] << 8) | buf[5]; + if (tlen > len) + return done; + + t->TracePacket(0, "TCP recv", tlen, buf); + + CArray data(buf, tlen); + std::unique_ptr packet(EIBNetIPPacket::fromPacket(data, routeBackAddr(), IPV4_TCP)); + if (!packet) + { + stop(true); + return done; + } + + handlePacket(*packet); + done += tlen; + buf += tlen; + len -= tlen; + } +} + +void TcpTunConn::timeout_cb(ev::timer &, int) +{ + TRACEPRINTF (t, 8, "Timeout for TCP connection"); + + stop(true); +} + +int TcpTunConn::getFreeChannelID() +{ + uint8_t res = this->lastChannelID; + + while (true) + { + res = (res + 1) & 0xff; + + // Channel res is free + if (this->channels.find(res) == this->channels.end()) + { + this->lastChannelID = res; + return res; + } + + // No channel is free + if (res == this->lastChannelID) + { + return -1; + } + } +} + +bool TcpTunConn::openChannel(const TunChannelPtr& channel) +{ + if (channels.find(channel->channelID) != channels.end()) + { + TRACEPRINTF (t, 8, "Attempting to reuse open channel ID"); + return false; + } + + if (!channel->setupChannel()) + { + TRACEPRINTF (t, 8, "Channel setup failed"); + channel->stop(true); + return false; + } + + this->channels[channel->channelID] = channel; + + return true; +} + +void TcpTunConn::closeChannel(const TunChannelPtr& channel) +{ + TRACEPRINTF (t, 8, "Closing channel %d", channel->channelID); + + channel->stop(false); + + this->channels.erase(channel->channelID); +} + +TunChannelPtr TcpTunConn::findChannel(uint8_t channelID) +{ + auto it = this->channels.find(channelID); + if (it == this->channels.end()) + return TunChannelPtr(); + return it->second; +} + +void TcpTunConn::stop(bool err) +{ + TRACEPRINTF (t, 8, "Stop Conn"); + + // Close all channels + while (true) + { + auto it = this->channels.begin(); + if (it == this->channels.end()) + break; + closeChannel(it->second); + } + + sendbuf.stop(); + recvbuf.stop(); + + close(fd); + fd = -1; + + timeout.stop(); + + parent->deregister(shared_from_this()); +} + +void +TcpTunConn::start() +{ + if (running) + return; + if (fd == -1) + return; + + sendbuf.start(); + recvbuf.start(); + + running = true; +} + +bool TcpTunConn::setup() +{ + return true; +} + +void +TcpTunConn::send(const EIBNetIPPacket& p) +{ + CArray data = p.ToPacket(); + + t->TracePacket(0, "TCP send", data.size(), data.data()); + + if (fd >= 0) + sendbuf.write(data.data(), data.size()); +} + +void +TcpTunConn::handlePacket(const EIBNetIPPacket &p1) +{ + if (p1.service == CONNECTIONSTATE_REQUEST) + { + EIBnet_ConnectionStateRequest r1; + EIBnet_ConnectionStateResponse r2; + + if (parseEIBnet_ConnectionStateRequest(p1, r1)) + { + t->TracePacket(2, "unparseable CONNECTIONSTATE_REQUEST", p1.data); + return; + } + + reset_timer(); + + r2.channel = r1.channel; + auto channel = findChannel(r1.channel); + if (!channel) + { + r2.status = E_CONNECTION_ID; + send(r2.ToPacket(IPV4_TCP)); + return; + } + + TRACEPRINTF (t, 8, "CONNECTIONSTATE_REQUEST"); + + send(r2.ToPacket(IPV4_TCP)); + return; + } + + if (p1.service == DISCONNECT_REQUEST) + { + EIBnet_DisconnectRequest r1; + EIBnet_DisconnectResponse r2; + if (parseEIBnet_DisconnectRequest(p1, r1)) + { + t->TracePacket (2, "unparseable DISCONNECT_REQUEST", p1.data); + return; + } + + reset_timer(); + + r2.channel = r1.channel; + auto channel = findChannel(r1.channel); + if (!channel) + { + r2.status = E_CONNECTION_ID; + send(r2.ToPacket(IPV4_TCP)); + return; + } + + TRACEPRINTF (t, 8, "DISCONNECT_REQUEST"); + + closeChannel(channel); + + r2.status = 0; + send(r2.ToPacket(IPV4_TCP)); + return; + } + + if (p1.service == CONNECTION_REQUEST) + { + EIBnet_ConnectRequest r1; + EIBnet_ConnectResponse r2; + // For TCP, the "Route Back" HPAI must be used. + // See ISO 22510:2019 section 5.2.8.6.2 + r2.daddr = routeBackAddr(); + if (parseEIBnet_ConnectRequest(p1, r1)) + { + t->TracePacket(2, "unparseable CONNECTION_REQUEST", p1.data); + return; + } + + reset_timer(); + + if (r1.CRI.size() == 3 && r1.CRI[0] == TUNNEL_CONNECTION) + { + int newChannelID = getFreeChannelID(); + if (newChannelID < 0) + { + TRACEPRINTF (t, 8, "Out of channel IDs"); + r2.status = E_NO_MORE_CONNECTIONS; + send(r2.ToPacket(IPV4_TCP)); + return; + } + + if (r1.CRI[1] == TUNNEL_LINKLAYER) + { + LinkConnectClientPtr link = LinkConnectClientPtr(new LinkConnectClient(std::dynamic_pointer_cast(parent->shared_from_this()), parent->tunnel_cfg, t)); + + auto chan = std::make_shared(shared_from_this(), newChannelID); + auto service = std::make_shared(chan, static_cast(parent->router), link); + chan->setService(service); + + link->set_driver(service); + + if (!link->setup()) + { + TRACEPRINTF (t, 8, "Tunnel CONNECTION_REQ link setup failed"); + r2.status = E_NO_MORE_CONNECTIONS; + send(r2.ToPacket(IPV4_TCP)); + chan->stop(true); + return; + } + + if (!static_cast(parent->router).registerLink(link, true)) + { + TRACEPRINTF (t, 8, "Tunnel CONNECTION_REQ registering link failed"); + r2.status = E_NO_MORE_CONNECTIONS; + send(r2.ToPacket(IPV4_TCP)); + chan->stop(true); + return; + } + + // Allocate an address + if (!service->allocAddress()) + { + TRACEPRINTF (t, 8, "Tunnel CONNECTION_REQ no free addresses"); + r2.status = E_NO_MORE_CONNECTIONS; + send(r2.ToPacket(IPV4_TCP)); + chan->stop(true); + return; + } + + if (openChannel(chan)) + { + r2.CRD.resize(3); + r2.CRD[0] = TUNNEL_CONNECTION; + TRACEPRINTF (t, 8, "Tunnel CONNECTION_REQ with %s", FormatEIBAddr(service->knxaddr)); + r2.CRD[1] = (service->knxaddr >> 8) & 0xFF; + r2.CRD[2] = (service->knxaddr >> 0) & 0xFF; + r2.status = E_NO_ERROR; + r2.channel = chan->channelID; + } + else + r2.status = E_TUNNELING_LAYER; + } + else if (r1.CRI[1] == TUNNEL_BUSMONITOR) + { + r2.CRD.resize(3); + r2.CRD[0] = TUNNEL_CONNECTION; + r2.CRD[1] = 0; + r2.CRD[2] = 0; + auto chan = std::make_shared(shared_from_this(), newChannelID); + chan->setService(std::make_shared(chan, static_cast(parent->router))); + if (openChannel(chan)) + { + r2.status = E_NO_ERROR; + r2.channel = chan->channelID; + } + else + r2.status = E_TUNNELING_LAYER; + } + else + { + r2.status = E_TUNNELING_LAYER; + TRACEPRINTF (t, 8, "bad CONNECTION_REQ: [1] x%02x", r1.CRI[1]); + send(r2.ToPacket(IPV4_TCP)); + return; + } + } + else if (r1.CRI.size() == 1 && r1.CRI[0] == DEVICE_MGMT_CONNECTION) + { + r2.CRD.resize(1); + r2.CRD[0] = DEVICE_MGMT_CONNECTION; + TRACEPRINTF (t, 8, "Tunnel CONNECTION_REQ, no addr (mgmt)"); + + int newChannelID = getFreeChannelID(); + if (newChannelID < 0) + { + TRACEPRINTF (t, 8, "Out of channel IDs"); + r2.status = E_NO_MORE_CONNECTIONS; + send(r2.ToPacket(IPV4_TCP)); + return; + } + + auto chan = std::make_shared(shared_from_this(), newChannelID); + chan->setService(std::make_shared(chan)); + + if (openChannel(chan)) + { + r2.status = E_NO_ERROR; + r2.channel = chan->channelID; + } + else + r2.status = E_TUNNELING_LAYER; + } + else + { + TRACEPRINTF (t, 8, "bad CONNECTION_REQ: size %d, [0] x%02x", r1.CRI.size(), r1.CRI[0]); + r2.status = E_CONNECTION_TYPE; + } + + send(r2.ToPacket(IPV4_TCP)); + return; + } + + if (p1.service == TUNNEL_REQUEST) + { + EIBnet_TunnelRequest r1; + EIBnet_TunnelACK r2; + if (parseEIBnet_TunnelRequest(p1, r1)) + { + t->TracePacket(2, "unparseable TUNNEL_REQUEST", p1.data); + return; + } + + reset_timer(); + + auto channel = findChannel(r1.channel); + if (!channel) + { + TRACEPRINTF (t, 8, "TUNNEL_REQUEST on unknown channel %d", r1.channel); + r2.status = E_CONNECTION_ID; + send(r2.ToPacket(IPV4_TCP)); + return; + } + + channel->receiveTunnelRequest(r1); + + return; + } + + if (p1.service == DEVICE_CONFIGURATION_REQUEST) + { + EIBnet_ConfigRequest r1; + EIBnet_ConfigACK r2; + if (parseEIBnet_ConfigRequest(p1, r1)) + { + t->TracePacket(2, "unparseable DEVICE_CONFIGURATION_REQUEST", p1.data); + return; + } + + reset_timer(); + + auto channel = findChannel(r1.channel); + if (!channel) + { + TRACEPRINTF (t, 8, "DEVICE_CONFIGURATION_REQUEST on unknown channel %d", r1.channel); + r2.status = E_CONNECTION_ID; + send(r2.ToPacket(IPV4_TCP)); + return; + } + + TRACEPRINTF (t, 8, "CONFIG_REQ on channel %d",r1.channel); + + channel->receiveConfigRequest(r1); + + return; + } + + TRACEPRINTF (t, 8, "Unexpected service type: %04x", p1.service); +} + +TcpTunServerBase::TcpTunServerBase(BaseRouter& r, IniSectionPtr& s) + : NetServerBase(r,s) + , tunnel_cfg(s->sub("tunnel",false)) +{ + t->setAuxName("tcptunsrv"); +} + +TcpTunServerBase::~TcpTunServerBase() +{ + if (fd >= 0) + close(fd); +} + +void +TcpTunServerBase::setupConnection(int cfd) +{ + int val = 1; + setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val)); +} + +ClientConnBasePtr +TcpTunServerBase::createConnection(int cfd) +{ + auto connection = std::shared_ptr(new TcpTunConn(this, ++lastConnectionID, cfd)); + + return connection; +} + +void +TcpTunServerBase::stop(bool err) +{ + if (fd >= 0) + { + close(fd); + fd = -1; + } + NetServerBase::stop(err); +} + +TcpTunServer::TcpTunServer(BaseRouter& r, IniSectionPtr& s) + : TcpTunServerBase(r,s) +{ + t->setAuxName("tcptunsrv"); +} + +bool +TcpTunServer::setup() +{ + if (!Server::setup()) + return false; + port = cfg->value("port", 3671); + keepalive = cfg->value("heartbeat-timeout", CONNECTION_ALIVE_TIME); + ignore_when_systemd = cfg->value("systemd-ignore", port == 3671); + + /* Check that we have client addresses. */ + if (!static_cast(router).hasClientAddrs()) + return false; + /* set up a temporary fake tunnel stack to test the arguments early. */ + if (!static_cast(router).checkStack(tunnel_cfg)) + return false; + + return true; +} + +void +TcpTunServer::start() +{ + int reuse = 1; + + if (ignore_when_systemd && static_cast(router).using_systemd) + { + ignore = true; + stopped(true); + return; + } + + struct sockaddr_in addr; + + TRACEPRINTF (t, 8, "OpenInetSocket %d", port); + memset(&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + { + ERRORPRINTF (t, E_ERROR | 149, "OpenInetSocket %d: socket: %s", port, strerror(errno)); + goto ex1; + } + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof (reuse)); + + if (bind(fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) + { + ERRORPRINTF (t, E_ERROR | 150, "OpenInetSocket %d: bind: %s", port, strerror(errno)); + goto ex2; + } + + if (listen(fd, 10) == -1) + { + ERRORPRINTF (t, E_ERROR | 154, "OpenSocket: listen: %s", strerror(errno)); + goto ex2; + } + + TRACEPRINTF (t, 8, "Socket opened"); + NetServerBase::start(); + return; + +ex2: + close(fd); + fd = -1; +ex1: + stop(true); + return; +} + +UnixTunServer::UnixTunServer(BaseRouter& r, IniSectionPtr& s) + : TcpTunServerBase(r,s) +{ + t->setAuxName("unixtunsrv"); +} + +bool +UnixTunServer::setup() +{ + if (!Server::setup()) + return false; + path = cfg->value("path", ""); + keepalive = cfg->value("heartbeat-timeout", CONNECTION_ALIVE_TIME); + ignore_when_systemd = cfg->value("systemd-ignore", false); + + /* Check that we have client addresses. */ + if (!static_cast(router).hasClientAddrs()) + return false; + /* set up a temporary fake tunnel stack to test the arguments early. */ + if (!static_cast(router).checkStack(tunnel_cfg)) + return false; + + return true; +} + +void +UnixTunServer::start() +{ + int reuse = 1; + + if (ignore_when_systemd && static_cast(router).using_systemd) + { + ignore = true; + stopped(true); + return; + } + + struct sockaddr_un addr; + + TRACEPRINTF (t, 8, "OpenUnixSocket '%s'", path); + memset(&addr, 0, sizeof (addr)); + addr.sun_family = AF_LOCAL; + strncpy(addr.sun_path, path.c_str(), sizeof (addr.sun_path) - 1); + + fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (fd == -1) + { + ERRORPRINTF (t, E_ERROR | 151, "OpenUnixSocket %s: socket: %s", path, strerror(errno)); + goto ex1; + } + + if (bind(fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) + { + /* + * dead file? + */ + if (errno == EADDRINUSE) + { + if (connect(fd, (struct sockaddr *) &addr, sizeof (addr)) == 0) + { +ex: + ERRORPRINTF (t, E_ERROR | 152, "OpenLocalSocket %s: bind: %s", path, strerror(errno)); + goto ex2; + } + else if (errno == ECONNREFUSED) + { + if (::unlink(path.c_str()) == -1 && errno != ENOENT) + { + ERRORPRINTF (t, E_ERROR | 155, "Existing socket %s: unlink: %s", path, strerror(errno)); + goto ex2; + } + if (bind(fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) + { + ERRORPRINTF (t, E_ERROR | 153, "Existing socket %s: bind: %s", path, strerror(errno)); + goto ex2; + } + } + else + { + ERRORPRINTF (t, E_ERROR | 153, "Existing socket %s: bind: %s", path, strerror(errno)); + goto ex2; + } + } + } + + if (listen(fd, 10) == -1) + { + ERRORPRINTF (t, E_ERROR | 154, "OpenSocket: listen: %s", strerror(errno)); + goto ex2; + } + + TRACEPRINTF (t, 8, "Socket opened"); + NetServerBase::start(); + return; + +ex2: + close(fd); + fd = -1; +ex1: + stop(true); + return; +} + +TcpTunSystemdServer::TcpTunSystemdServer(BaseRouter& r, IniSectionPtr& s, int systemd_fd) + : TcpTunServerBase(r,s) +{ + t->setAuxName("systemd_tcptunsrv"); + fd = systemd_fd; +} + +void +TcpTunSystemdServer::start() +{ + TRACEPRINTF (t, 8, "OpenSystemdSocket %d", fd); + if (fd < 0) + { + stopped(true); + return; + } + + if (listen(fd, 10) == -1) + { + ERRORPRINTF (t, E_ERROR | 148, "OpenSystemdSocket: listen: %s", strerror(errno)); + TcpTunServerBase::stop(true); + return; + } + + TRACEPRINTF (t, 8, "SystemdSocket %d opened", fd); + NetServerBase::start(); +} + +bool +TcpTunSystemdServer::setup() +{ + if (!Server::setup()) + return false; + keepalive = cfg->value("heartbeat-timeout", CONNECTION_ALIVE_TIME); + + /* Check that we have client addresses. */ + if (!static_cast(router).hasClientAddrs()) + return false; + /* set up a temporary fake tunnel stack to test the arguments early. */ + if (!static_cast(router).checkStack(tunnel_cfg)) + return false; + + return true; +} + +void +TcpTunSystemdServer::stop(bool err) +{ + TcpTunServerBase::stop(err); +} + +TcpTunSystemdServer::~TcpTunSystemdServer() +{ + if (fd >= 0) + { + close(fd); + fd = -1; + } +} diff -Nru knxd-0.14.54.1/src/libserver/tcptunserver.h knxd-0.14.69/src/libserver/tcptunserver.h --- knxd-0.14.54.1/src/libserver/tcptunserver.h 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/src/libserver/tcptunserver.h 2024-12-16 15:40:26.000000000 +0000 @@ -0,0 +1,148 @@ +/* + EIBD eib bus access and management daemon + Copyright (C) 2005-2011 Martin Koegler + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/** + * @file + * @ingroup KNX_03_08_01 + * KNXnet/IP + * @{ + */ + +#ifndef TCPTUN_SERVER_H +#define TCPTUN_SERVER_H + +#include "eibnetip.h" +#include "server.h" +#include "client.h" + +class TunChannel; +using TunChannelPtr = std::shared_ptr; + +class TcpTunConn; +using TcpTunConnPtr = std::shared_ptr; + +class TcpTunServerBase; +using TcpTunServerBasePtr = std::shared_ptr; + +/** Driver for tunnels */ +class TcpTunConn : public ClientConnectionBase, public std::enable_shared_from_this +{ +public: + TcpTunConn(TcpTunServerBase *parent, uint32_t connectionID, int fd); + virtual ~TcpTunConn(); + bool setup() override; + void start() override; + void stop(bool err) override; + + TracePtr t; + TcpTunServerBase *parent; + + ev::timer timeout; + void timeout_cb(ev::timer &w, int revents); + void reset_timer(); + + size_t read_cb(uint8_t *buf, size_t len); + void error_cb(); + + void handlePacket(const EIBNetIPPacket &p1); + + // Return the next free channel ID, or -1 if no channels are available + int getFreeChannelID(); + bool openChannel(const TunChannelPtr& channel); + void closeChannel(const TunChannelPtr& channel); + // Return the channel with ID channelID or nullptr if there is no such channel + TunChannelPtr findChannel(uint8_t channelID); + + void send(const EIBNetIPPacket& p); + +protected: + uint32_t connectionID; + + SendBuf sendbuf; + RecvBuf recvbuf; + int fd; + + uint8_t lastChannelID = 0; + std::map channels; +}; + +class TcpTunServerBase : public NetServerBase +{ + friend class TcpTunConn; + +public: + TcpTunServerBase(BaseRouter& r, IniSectionPtr& s); + virtual ~TcpTunServerBase(); + + void stop(bool err) override; + + ClientConnBasePtr createConnection(int cfd) override; + +protected: + void setupConnection(int cfd) override; + +private: + uint32_t lastConnectionID = 0; + +protected: + /** config */ + ev::tstamp keepalive; + IniSectionPtr tunnel_cfg; +}; + +SERVER_(TcpTunServer,TcpTunServerBase,tcptunsrv) +{ +public: + TcpTunServer(BaseRouter& r, IniSectionPtr& s); + + bool setup() override; + void start() override; + +private: + /** config */ + uint16_t port; +}; + +SERVER_(UnixTunServer,TcpTunServerBase,unixtunsrv) +{ +public: + UnixTunServer(BaseRouter& r, IniSectionPtr& s); + + bool setup() override; + void start() override; + +private: + /** config */ + std::string path; +}; + +class TcpTunSystemdServer : public TcpTunServerBase +{ +public: + TcpTunSystemdServer(BaseRouter& r, IniSectionPtr& s, int systemd_fd); + ~TcpTunSystemdServer() override; + + bool setup() override; + void start() override; + void stop(bool err) override; +}; + +#endif + +/** @} */ diff -Nru knxd-0.14.54.1/src/libserver/tunchannel.cpp knxd-0.14.69/src/libserver/tunchannel.cpp --- knxd-0.14.54.1/src/libserver/tunchannel.cpp 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/src/libserver/tunchannel.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -0,0 +1,401 @@ +/* + EIBD eib bus access and management daemon + Copyright (C) 2005-2011 Martin Koegler + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "tunchannel.h" +#include "tcptunserver.h" + +TunChannel::TunChannel(const TcpTunConnPtr& connection, uint8_t channelID) + : t(TracePtr(new Trace(*connection->t))) + , connection(connection) + , channelID(channelID) +{ + char buf[10]; + snprintf(buf, sizeof(buf), "-%02x", channelID); + t->setAuxName(connection->t->auxname + buf); +} + +TunChannel::~TunChannel() +{ + TRACEPRINTF (t, 8, "Close TunChannel"); +} + +void TunChannel::setService(const TunServicePtr& service) +{ + if (this->service) + { + TRACEPRINTF (t, 8, "Service is already set"); + return; + } + + TRACEPRINTF (t, 8, "Setting service"); + + this->service = service; +} + +bool TunChannel::setupChannel() +{ + if (!this->service) + { + TRACEPRINTF (t, 8, "Service not set"); + return false; + } + + return service->setupService(); +} + +void TunChannel::start() +{ + service->start(); +} + +void TunChannel::stop(bool err) +{ + service->stop(err); +} + +void TunChannel::sendTunnelRequest(const CArray& cemi) +{ + auto connection = this->connection.lock(); + if (!connection) + { + TRACEPRINTF (t, 8, "Attempt to send tunnel request without a connection"); + return; + } + + EIBnet_TunnelRequest r; + r.channel = channelID; + r.seqno = sno; + r.CEMI = cemi; + connection->send(r.ToPacket(IPV4_TCP)); + sno = (sno + 1) & 0xff; +} + +void TunChannel::sendConfigRequest(const CArray& cemi) +{ + auto connection = this->connection.lock(); + if (!connection) + { + TRACEPRINTF (t, 8, "Attempt to send config request without a connection"); + return; + } + + EIBnet_ConfigRequest r; + r.channel = channelID; + r.seqno = sno; + r.CEMI = cemi; + connection->send(r.ToPacket(IPV4_TCP)); + sno = (sno + 1) & 0xff; +} + +void TunChannel::receiveTunnelRequest(EIBnet_TunnelRequest &r1) +{ + // On UDP, the sequence number would be checked here, but for TCP the sequence + // number is not checked. See ISO 22510:2019 section 5.2.5.3.4 + // if (rno != r1.seqno) + // { + // TRACEPRINTF (t, 8, "Wrong tunnel sequence number %d<->%d", + // r1.seqno, rno); + // } + rno++; + + if (!service) + { + TRACEPRINTF (t, 8, "No tunnel service set"); + return; + } + + uint8_t status = service->handleTunnelRequest(r1); + + // Note: There are no TUNNELLING_ACKs with TCP, so no way to return the status + if (status) + TRACEPRINTF (t, 8, "TCP TUNNELLING_REQUEST failed (%d)", status); +} + +void TunChannel::receiveConfigRequest(EIBnet_ConfigRequest &r1) +{ + // On UDP, the sequence number would be checked here, but for TCP the sequence + // number is not checked. See ISO 22510:2019 section 5.2.5.3.4 + // if (rno != r1.seqno) + // { + // TRACEPRINTF (t, 8, "Wrong config sequence number %d<->%d", + // r1.seqno, rno); + // } + rno++; + + if (!service) + { + TRACEPRINTF (t, 8, "No tunnel service set"); + return; + } + + uint8_t status = service->handleConfigRequest(r1); + + // Note: There are no DEVICE_CONFIGURATION_ACKs with TCP, so no way to return + // the status + if (status) + TRACEPRINTF (t, 8, "TCP DEVICE_CONFIGURATION_REQUEST failed (%d)", status); +} + +TunService::TunService(const TunChannelPtr& channel) + : t(channel->t) + , channel(channel) +{ +} + +TunService::~TunService() +{ +} + +// This method is overwritten on channel classes which expect to receive +// TUNNELLING_REQUEST packets +ErrorCode TunService::handleTunnelRequest(EIBnet_TunnelRequest &r1) +{ + TRACEPRINTF (t, 8, "Got unexpected TUNNELLING_REQUEST"); + return E_TUNNELING_LAYER; +} + +// This method is overwritten on channel classes which expect to receive +// DEVICE_CONFIGURATION_REQUEST packets +ErrorCode TunService::handleConfigRequest(EIBnet_ConfigRequest &r1) +{ + TRACEPRINTF (t, 8, "Got unexpected DEVICE_CONFIGURATION_REQUEST"); + return E_KNX_CONNECTION; +} + +TunServiceLinkLayer::TunServiceLinkLayer(const TunChannelPtr& channel, Router& router, LinkConnectClientPtr c) + : SubDriver(c) + , TunService(channel) + , router(router) +{ + SubDriver::t->setAuxName(channel->t->auxname); +} + +TunServiceLinkLayer::~TunServiceLinkLayer() +{ +} + +bool TunServiceLinkLayer::setupService() +{ + addAddress(knxaddr); + + return true; +} + +bool TunServiceLinkLayer::setup() +{ + if (!SubDriver::setup()) + return false; + + return true; +} + +void TunServiceLinkLayer::start() +{ + SubDriver::start(); +} + +void TunServiceLinkLayer::stop(bool err) +{ + freeAddress(); + + auto c = std::dynamic_pointer_cast(conn.lock()); + if (c != nullptr) + router.unregisterLink(c); + + SubDriver::stop(err); +} + +void TunServiceLinkLayer::send_L_Data (LDataPtr l) +{ + auto channel_ptr = this->channel.lock(); + if (channel_ptr) + channel_ptr->sendTunnelRequest(L_Data_ToCEMI(0x29, l)); + + send_Next(); +} + +ErrorCode TunServiceLinkLayer::handleTunnelRequest(EIBnet_TunnelRequest &r1) +{ + TRACEPRINTF (t, 8, "TUNNEL_REQ"); + + LDataPtr c = CEMI_to_L_Data(r1.CEMI, t); + if (!c) + return E_DATA_CONNECTION; + + if (c->source_address == 0) + c->source_address = knxaddr; + + if (r1.CEMI[0] == 0x11) + { + // Send L_Data.con message + auto channel_ptr = this->channel.lock(); + if (channel_ptr) + channel_ptr->sendTunnelRequest(L_Data_ToCEMI(0x2E, c)); + } + + if (r1.CEMI[0] == 0x11 || r1.CEMI[0] == 0x29) + { + recv_L_Data(std::move(c)); + return E_NO_ERROR; + } + else + { + TRACEPRINTF (t, 8, "Wrong leader x%02x", r1.CEMI[0]); + return E_TUNNELING_LAYER; + } +} + +bool TunServiceLinkLayer::allocAddress() +{ + // Channel can have only one address + if (knxaddr) + return false; + + knxaddr = router.get_client_addr(t); + if (!knxaddr) + // Out of addresses + return false; + + t->setAuxName(FormatEIBAddr(knxaddr)); + + return true; +} + +void TunServiceLinkLayer::freeAddress() +{ + if (!knxaddr) + return; + + router.release_client_addr(knxaddr); + knxaddr = 0; + t->setAuxName("no-addr"); +} + +TunServiceBusMonitor::TunServiceBusMonitor(const TunChannelPtr& channel, Router& router) + : TunService(channel) + , L_Busmonitor_CallBack(channel->t->name) + , router(router) +{ +} + +TunServiceBusMonitor::~TunServiceBusMonitor() +{ +} + +bool TunServiceBusMonitor::setupService() +{ + if (!router.registerVBusmonitor(this)) + return false; + + return true; +} + +void TunServiceBusMonitor::start() +{ +} + +void TunServiceBusMonitor::stop(bool err) +{ + router.deregisterVBusmonitor(this); +} + +void TunServiceBusMonitor::send_L_Busmonitor(LBusmonPtr l) +{ + auto channel_ptr = this->channel.lock(); + if (channel_ptr) + channel_ptr->sendTunnelRequest(Busmonitor_to_CEMI(0x2B, l, no)); + + no++; +} + +TunServiceConfig::TunServiceConfig(const TunChannelPtr& channel) + : TunService(channel) +{ +} + +TunServiceConfig::~TunServiceConfig() +{ +} + +bool TunServiceConfig::setupService() +{ + return true; +} + +void TunServiceConfig::start() +{ +} + +void TunServiceConfig::stop(bool err) +{ +} + +ErrorCode TunServiceConfig::handleConfigRequest(EIBnet_ConfigRequest &r1) +{ + if (r1.CEMI.size() == 0) + return E_DATA_CONNECTION; + + if (r1.CEMI[0] == 0xFC) // M_PropRead.req + { + if (r1.CEMI.size() == 7) + { + CArray res, CEMI; + int obj = (r1.CEMI[1] << 8) | r1.CEMI[2]; + int objno = r1.CEMI[3]; + int prop = r1.CEMI[4]; + int count = (r1.CEMI[5] >> 4) & 0x0f; + int start = (r1.CEMI[5] & 0x0f) | r1.CEMI[6]; + res.resize(1); + res[0] = 0; + if (obj == 0 && objno == 0) + { + if (prop == 0) + { + res.resize(2); + res[0] = 0; + res[1] = 0; + start = 0; + } + else + count = 0; + } + else + count = 0; + CEMI.resize(6 + res.size()); + CEMI[0] = 0xFB; + CEMI[1] = (obj >> 8) & 0xff; + CEMI[2] = obj & 0xff; + CEMI[3] = objno; + CEMI[4] = prop; + CEMI[5] = ((count & 0x0f) << 4) | (start >> 8); + CEMI[6] = start & 0xff; + CEMI.setpart(res, 7); + + auto channel_ptr = this->channel.lock(); + if (channel_ptr) + channel_ptr->sendConfigRequest(CEMI); + + return E_NO_ERROR; + } + else + return E_DATA_CONNECTION; + } + else + return E_DATA_CONNECTION; +} diff -Nru knxd-0.14.54.1/src/libserver/tunchannel.h knxd-0.14.69/src/libserver/tunchannel.h --- knxd-0.14.54.1/src/libserver/tunchannel.h 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/src/libserver/tunchannel.h 2024-12-16 15:40:26.000000000 +0000 @@ -0,0 +1,151 @@ +/* + EIBD eib bus access and management daemon + Copyright (C) 2005-2011 Martin Koegler + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/** + * @file + * @ingroup KNX_03_08_01 + * KNXnet/IP + * @{ + */ + +#ifndef TUNCHANNEL_H +#define TUNCHANNEL_H + +#include "eibnetip.h" +#include "link.h" +#include "router.h" + +class TunChannel; +using TunChannelPtr = std::shared_ptr; + +class TunService; +using TunServicePtr = std::shared_ptr; + +class TcpTunConn; +using TcpTunConnPtr = std::shared_ptr; + +class TunChannel +{ +public: + TunChannel(const TcpTunConnPtr& connection, uint8_t channelID); + virtual ~TunChannel(); + + void setService(const TunServicePtr& service); + + bool setupChannel(); + void start(); + void stop(bool err); + + void sendTunnelRequest(const CArray& cemi); + void sendConfigRequest(const CArray& cemi); + + // handle various packets from the connection + void receiveTunnelRequest(EIBnet_TunnelRequest &r1); + void receiveConfigRequest(EIBnet_ConfigRequest &r1); + + TracePtr t; + std::weak_ptr connection; + TunServicePtr service; + uint8_t channelID; + + // Sending sequence counter + uint8_t sno = 0; + // Receiving sequence counter + uint8_t rno = 0; +}; + +class TunService +{ +public: + TunService(const std::shared_ptr& channel); + virtual ~TunService(); + + virtual bool setupService() = 0; + virtual void start() = 0; + virtual void stop(bool err) = 0; + + virtual ErrorCode handleTunnelRequest(EIBnet_TunnelRequest& r1); + virtual ErrorCode handleConfigRequest(EIBnet_ConfigRequest &r1); + + TracePtr t; + std::weak_ptr channel; +}; + +class TunServiceLinkLayer : public SubDriver, public TunService +{ +public: + using TunService::t; + + TunServiceLinkLayer(const std::shared_ptr& channel, Router& router, LinkConnectClientPtr c); + virtual ~TunServiceLinkLayer(); + + ErrorCode handleTunnelRequest(EIBnet_TunnelRequest& r1) override; + + bool setupService() override; + void start() override; + void stop(bool err) override; + + bool setup() override; + + void send_L_Data(LDataPtr l) override; + + bool allocAddress(); + void freeAddress(); + + bool hasAddress(eibaddr_t a) const override + { + return knxaddr && knxaddr == a; + } + + Router& router; + eibaddr_t knxaddr = 0; +}; + +class TunServiceBusMonitor : public TunService, public L_Busmonitor_CallBack +{ +public: + TunServiceBusMonitor(const std::shared_ptr& channel, Router& router); + virtual ~TunServiceBusMonitor(); + + bool setupService() override; + void start() override; + void stop(bool err) override; + + void send_L_Busmonitor(LBusmonPtr l) override; + + Router& router; + int no = 1; +}; + +class TunServiceConfig : public TunService +{ +public: + TunServiceConfig(const std::shared_ptr& channel); + virtual ~TunServiceConfig(); + + bool setupService() override; + void start() override; + void stop(bool err) override; + + ErrorCode handleConfigRequest(EIBnet_ConfigRequest &r1) override; +}; + +#endif + +/** @} */ diff -Nru knxd-0.14.54.1/src/libserver/usblowlevel.cpp knxd-0.14.69/src/libserver/usblowlevel.cpp --- knxd-0.14.54.1/src/libserver/usblowlevel.cpp 2021-01-02 10:22:00.000000000 +0000 +++ knxd-0.14.69/src/libserver/usblowlevel.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -28,6 +28,10 @@ #include "usb.h" +/* add formatter for fmt >= 10.0.0 */ +int format_as(UState t) { return t; } +int format_as(libusb_transfer_status t) { return t; } + USBEndpoint parseUSBEndpoint (IniSectionPtr s) { diff -Nru knxd-0.14.54.1/src/server/Makefile.am knxd-0.14.69/src/server/Makefile.am --- knxd-0.14.54.1/src/server/Makefile.am 2021-01-02 10:22:00.000000000 +0000 +++ knxd-0.14.69/src/server/Makefile.am 2024-12-16 15:40:26.000000000 +0000 @@ -3,7 +3,7 @@ AM_CPPFLAGS=-I$(top_srcdir)/src/libserver -I$(top_srcdir)/src/backend -I$(top_srcdir)/src/common -I$(top_srcdir)/src/usb $(LIBUSB_CFLAGS) $(SYSTEMD_CFLAGS) -Wno-missing-field-initializers knxd_CPPFLAGS=$(AM_CPPFLAGS) -DLIBEXECDIR="\"$(libexecdir)\"" -knxd_LDFLAGS=-Wl,$(LINK_ALL),../backend/libbackend.a,../libserver/libserver.a,$(NO_LINK_ALL) +knxd_LDFLAGS=-Wl$(LINK_ALL)$(LINK_FORCE),../backend/libbackend.a$(LINK_FORCE),../libserver/libserver.a$(NO_LINK_ALL) knxd_LDADD=../libserver/libeibstack.a ../common/libcommon.a ../usb/libusb.a $(LIBUSB_LIBS) $(SYSTEMD_LIBS) $(EV_LIBS) knxd_DEPENDENCIES=../libserver/libserver.a ../backend/libbackend.a ../libserver/libeibstack.a ../common/libcommon.a ../usb/libusb.a knxd_args_DEPENDENCIES=../common/libcommon.a diff -Nru knxd-0.14.54.1/src/tools/common.c knxd-0.14.69/src/tools/common.c --- knxd-0.14.54.1/src/tools/common.c 2020-03-06 14:05:31.000000000 +0000 +++ knxd-0.14.69/src/tools/common.c 2024-12-16 15:40:26.000000000 +0000 @@ -48,11 +48,11 @@ eibaddr_t readaddr (const char *addr) { - int a, b, c; - if (sscanf (addr, "%d.%d.%d", &a, &b, &c) == 3) - return ((a & 0x0f) << 12) | ((b & 0x0f) << 8) | ((c & 0xff)); - if (sscanf (addr, "%x", &a) == 1) - return a & 0xffff; + unsigned int a, b, c, n; + if (sscanf (addr, "%u.%u.%u%n", &a, &b, &c, &n) == 3 && addr[n] == '\0' && a <= 0x0F && b <= 0x0F && c <= 0xFF) + return (a << 12) | (b << 8) | c; + if (sscanf (addr, "%x%n", &a, &n) == 1 && addr[n] == '\0' && a <= 0xFFFF) + return a; die ("invalid individual address %s", addr); } @@ -71,15 +71,14 @@ eibaddr_t readgaddr (const char *addr) { - unsigned int a, b, c, res; - res = sscanf (addr, "%u/%u/%u", &a, &b, &c); - if (res == 3 && a <= 0x1F && b <= 0x07 && c <= 0xFF) + unsigned int a, b, c, n; + if (sscanf (addr, "%u/%u/%u%n", &a, &b, &c, &n) == 3 && addr[n] == '\0' && a <= 0x1F && b <= 0x07 && c <= 0xFF) return (a << 11) | (b << 8) | c; - if (res == 2 && a <= 0x1F && b <= 0x7FF) - return (a << 11) | (b & 0x7FF); - if (sscanf (addr, "%x", &a) == 1 && a <= 0xFFFF) + if (sscanf (addr, "%u/%u%n", &a, &b, &n) == 2 && addr[n] == '\0' && a <= 0x1F && b <= 0x7FF) + return (a << 11) | b; + if (sscanf (addr, "%x%n", &a, &n) == 1 && addr[n] == '\0' && a <= 0xFFFF) return a; - die ("invalid group address format %s", addr); + die ("invalid group address %s", addr); } unsigned diff -Nru knxd-0.14.54.1/src/tools/eibread-cgi.c knxd-0.14.69/src/tools/eibread-cgi.c --- knxd-0.14.54.1/src/tools/eibread-cgi.c 2021-03-16 18:52:28.000000000 +0000 +++ knxd-0.14.69/src/tools/eibread-cgi.c 2024-12-16 15:40:26.000000000 +0000 @@ -39,12 +39,15 @@ int timeout = 300; int subscribedGA[UINT16 >>3]; int seenGA[UINT16 >>3]; -//int gaDPT[UINT16]; -//struct gaconfig_s { -// int ga; -// int dpt; -//}; +#if 0 +int gaDPT[UINT16]; + +struct gaconfig_s { + int ga; + int dpt; +}; +#endif @@ -65,7 +68,7 @@ void cgidie (const char *msg) { - printf ("{'error': '%s'}\n", msg); + printf ("{\"error\": \"%s\"}\n", msg); exit (1); } @@ -77,7 +80,7 @@ char *contentlen; char *cgi_str; - // check METHOD + /* check METHOD */ if( NULL == request ) return NULL; else if( strcmp(request, "GET") == 0 ) @@ -99,7 +102,7 @@ else { size = (unsigned long) atoi(contentlen); - if(size <= 0 && size > MAX_POSTSIZE) //avoid insane + if(size > MAX_POSTSIZE) /* avoid insane */ return NULL; } buffer =(char *) malloc(size+1); @@ -167,7 +170,7 @@ char fname[] = "/etc/wiregate/eibga.conf"; FILE* fp; /*Declare file pointer variable*/ char buf[BUFSIZE], *tok; - //char *buf, *tok; + /* char *buf, *tok; */ int hg,mg,ga; int currentga=0,ptr; if ((fp = fopen(fname,"r")) == NULL) @@ -183,10 +186,12 @@ { currentga=((hg & 0x01f) << 11) | ((mg & 0x07) << 8) | ((ga & 0xff)); } -// else if (currentga && (ptr=strstr(tok,"DPTId")) ) -// { -// sscanf(tok,"%*s = %d",&gaDPT[currentga]); -// } +#if 0 + else if (currentga && (ptr=strstr(tok,"DPTId")) ) + { + sscanf(tok,"%*s = %d",&gaDPT[currentga]); + } +#endif } }/*until EOF*/ fclose(fp); @@ -194,7 +199,7 @@ #endif -// read parameters +/* read parameters */ void readParseCGI() { char *param,*nextp; @@ -253,10 +258,10 @@ subscribedGA[ga >> 3] |= 1<<(ga&7); } } - //FIXME: Session,filter? + /* FIXME: Session,filter? */ else { - //printf ("Unknown param %s\n",value); //debug + /* printf ("Unknown param %s\n",value); // debug */ } } } @@ -278,12 +283,11 @@ time_t tstart; char seen = 0; tstart = time(NULL); - //strcat(outbuf,"Content-Type: application/json\n\n"); - //printf("Content-Type: application/json\n\n"); - printf("Content-Type: text/plain\r\n\r\n"); //workaround for uhttpd + /* strcat(outbuf,"Content-Type: application/json\n\n"); */ + printf("Content-Type: text/plain\r\n\r\n"); /* workaround for uhttpd */ readParseCGI(); - //readConfig(); + /* readConfig(); */ if (*eiburl == NULL) *eiburl = "local:/run/knx"; @@ -296,16 +300,18 @@ memset(seenGA,0,sizeof(seenGA)); - if (lastpos==0) // initial read from the bus + if (lastpos==0) /* initial read from the bus */ { - for (i = 1; i < UINT16; i++) // skip all-zero GA + for (i = 1; i < UINT16; i++) /* skip all-zero GA */ { if ((subscribedGA[i>>3]&(1<<((i&7)))) || (subscribedGA[0] & 1)) { dest = i; len_gread = EIB_Cache_Read_Sync (con, dest, &src, sizeof (buf_gread), buf_gread, 0); - //printf("%d/%d/%d",(dest >> 11) & 0x1f, (dest >> 8) & 0x07, dest & 0xff); //debug - //printf(" %d len %d %c",dest,len_gread,buf_gread[1]); //debug +#if 0 /* debug */ + printf("%d/%d/%d",(dest >> 11) & 0x1f, (dest >> 8) & 0x07, dest & 0xff); + printf(" %d len %d %c",dest,len_gread,buf_gread[1]); +#endif if (len_gread >= 0) { if (buf_gread[1] & 0xC0) @@ -333,7 +339,7 @@ } else { - //printf ("read failed!\n"); + /* printf ("read failed!\n"); */ } } } @@ -348,14 +354,14 @@ for (i = 0; i < len; i += 2) { dest = (buf[i] << 8) | buf[i + 1]; - // and output only one if changed multiple times to save the planet + /* and output only one if changed multiple times to save the planet */ if (seenGA[dest>>3]&(1<<((dest&7)))) continue; seenGA[dest>>3] |= 1<<((dest&7)); if ((subscribedGA[dest>>3]&(1<<((dest&7)))) || (subscribedGA[0] & 1)) { - // read value from cache + /* read value from cache */ len_gread = EIB_Cache_Read (con, dest, &src, sizeof(buf_gread), buf_gread); if (len_gread != -1) { @@ -366,8 +372,10 @@ else seen=1; - //sprintf (tmpbuf,"%d,\"%s",dest, decodeDPT(buf_gread[j+2],gaDPT[dest])); - //sprintf (tmpbuf,"%d,\"YES %02X", dest, buf_gread[1] & 0x3F); +#if 0 + sprintf (tmpbuf,"%d,\"%s",dest, decodeDPT(buf_gread[j+2],gaDPT[dest])); + sprintf (tmpbuf,"%d,\"YES %02X", dest, buf_gread[1] & 0x3F); +#endif if (len_gread == 2) { outptr += snprintf (outptr,OPL, "\"%d/%d/%d\":\"%02X", (dest >> 11) & 0x1f, (dest >> 8) & 0x07, dest & 0xff, buf_gread[1] & 0x3F); @@ -379,7 +387,7 @@ { outptr += snprintf (outptr,OPL, "%02X", buf_gread[j+2]); } - //printHex (len_gread - 2, buf_gread + 2); + /* printHex (len_gread - 2, buf_gread + 2); */ } *outptr++ = '"'; } diff -Nru knxd-0.14.54.1/src/tools/eibwrite-cgi.c knxd-0.14.69/src/tools/eibwrite-cgi.c --- knxd-0.14.54.1/src/tools/eibwrite-cgi.c 2020-03-06 14:05:31.000000000 +0000 +++ knxd-0.14.69/src/tools/eibwrite-cgi.c 2024-12-16 15:40:26.000000000 +0000 @@ -40,7 +40,7 @@ void cgidie (const char *msg) { - printf ("{'error': '%s'}\n", msg); + printf ("{\"error\": \"%s\"}\n", msg); exit (1); } @@ -52,7 +52,7 @@ char *contentlen; char *cgi_str; - // check METHOD + /* check METHOD */ if( NULL == request ) return NULL; else if( strcmp(request, "GET") == 0 ) @@ -74,7 +74,7 @@ else { size = (unsigned long) atoi(contentlen); - if(size <= 0 && size > MAX_POSTSIZE) //avoid insane + if(size <= 0 && size > MAX_POSTSIZE) /* avoid insane */ return NULL; } buffer =(char *) malloc(size+1); @@ -138,7 +138,7 @@ return 1; } -// read parameters +/* read parameters */ void readParseCGI() { char* params; @@ -200,7 +200,7 @@ } else { - //printf ("Unknown param %s\n",value); //debug + /* printf ("Unknown param %s\n",value); // debug */ } } @@ -248,7 +248,7 @@ buf[i+1] = j; len++; } - // only allow A_GroupValue_Write + /* only allow A_GroupValue_Write */ if ((buf[1] &0x80) != 0x80) cgidie ("Only A_GroupValue_Write allowed"); break; @@ -257,7 +257,7 @@ len=2; break; case 3: - // EIS2/DPT3 4bit dim + /* EIS2/DPT3 4bit dim */ buf[1] |= atoi(data) & 0x3f; len=2; break; @@ -283,7 +283,7 @@ i = sign | (exp << 11) | (mant & 0x07ff); buf[2] = i >> 8; buf[3] = i & 0xff; - //return $data >> 8, $data & 0xff; + /* return $data >> 8, $data & 0xff; */ len=4; break; case 16: @@ -298,10 +298,12 @@ len = EIBSendAPDU (con, len, buf); if (len == -1) cgidie ("Request failed"); - printf ("{'success':%d}\n",len-1); //don't confuse client with leading 0x00 + printf ("{\"success\":%d}\n",len-1); /*don't confuse client with leading 0x00 */ - //printf("size %d %d\n",sizeof(buf),strlen(buf)); - //printf("buf 0x%02X 0x%02X 0x%02X 0x%02X v:%s l:%d\n" ,buf[1],buf[2],buf[3],buf[4],data,strlen(data)); +#if 0 + printf("size %d %d\n",sizeof(buf),strlen(buf)); + printf("buf 0x%02X 0x%02X 0x%02X 0x%02X v:%s l:%d\n" ,buf[1],buf[2],buf[3],buf[4],data,strlen(data)); +#endif EIBClose (con); return 0; } diff -Nru knxd-0.14.54.1/src/tools/knxtool.c knxd-0.14.69/src/tools/knxtool.c --- knxd-0.14.54.1/src/tools/knxtool.c 2021-12-06 10:25:46.000000000 +0000 +++ knxd-0.14.69/src/tools/knxtool.c 2024-12-16 15:40:26.000000000 +0000 @@ -287,7 +287,7 @@ int m = d1 & 0x7ff; int ex = (d1 & 0x7800) >> 11; float temp = ((float) m * (1 << ex) / 100); - // printf ("d1=%d;m=%d;ex=%d;temp=%f\n", d1, m, ex, temp); + /* printf ("d1=%d;m=%d;ex=%d;temp=%f\n", d1, m, ex, temp); */ printf ("%2.1f", temp); } else @@ -379,7 +379,7 @@ char logfile[32]; FILE *new_fd; prev_day = loctim->tm_yday; - snprintf (logfile, 31, "knx-%d-%d-%d.log", + snprintf (logfile, 31, "knx-%hd-%02hd-%02hd.log", loctim->tm_year + 1900, loctim->tm_mon + 1, loctim->tm_mday); @@ -398,7 +398,7 @@ fprintf (log_fd, "Logfile opened\n"); } } - fprintf (log_fd, "%d-%02d-%02d %d:%d:%d : %s\n", + fprintf (log_fd, "%d-%02d-%02d %02d:%02d:%02d : %s\n", loctim->tm_year + 1900, loctim->tm_mon + 1, loctim->tm_mday, @@ -1490,7 +1490,7 @@ } else if (strcmp (prog, "vbusmonitor1time") == 0) { - // hires-time + /* hires-time */ struct timeval tv; struct tm* ptm; char time_string[40]; diff -Nru knxd-0.14.54.1/src/usb/findknxusb.cpp knxd-0.14.69/src/usb/findknxusb.cpp --- knxd-0.14.54.1/src/usb/findknxusb.cpp 2020-03-06 14:05:31.000000000 +0000 +++ knxd-0.14.69/src/usb/findknxusb.cpp 2024-12-16 15:40:26.000000000 +0000 @@ -123,7 +123,6 @@ fprintf (stderr, "libusb init failure\n"); exit (1); } - libusb_set_debug (context, 0); printf ("Possible addresses for KNX USB devices:\n"); count = libusb_get_device_list (context, &devs); diff -Nru knxd-0.14.54.1/systemd/Makefile.am knxd-0.14.69/systemd/Makefile.am --- knxd-0.14.54.1/systemd/Makefile.am 2021-01-02 10:22:00.000000000 +0000 +++ knxd-0.14.69/systemd/Makefile.am 2024-12-16 15:40:26.000000000 +0000 @@ -1,5 +1,5 @@ if HAVE_SYSTEMD -systemdsystemunit_DATA=knxd.service knxd.socket +systemdsystemunit_DATA=knxd.service knxd.socket knxd-net.socket sysconf_DATA=knxd.conf systemdsysusers_DATA=sysusers.d/knxd.conf all: knxd.service.exp diff -Nru knxd-0.14.54.1/systemd/knxd-net.socket.in knxd-0.14.69/systemd/knxd-net.socket.in --- knxd-0.14.54.1/systemd/knxd-net.socket.in 1970-01-01 00:00:00.000000000 +0000 +++ knxd-0.14.69/systemd/knxd-net.socket.in 2024-12-16 15:40:26.000000000 +0000 @@ -0,0 +1,12 @@ +[Unit] +Description=KNXnet/IP socket + +[Socket] +FileDescriptorName=knxnet +ListenStream=@RUNDIR@/knxnet +SocketGroup=knxd +SocketMode=0660 +Service=knxd.service + +[Install] +WantedBy=sockets.target diff -Nru knxd-0.14.54.1/systemd/knxd.conf knxd-0.14.69/systemd/knxd.conf --- knxd-0.14.54.1/systemd/knxd.conf 2018-11-16 13:55:14.000000000 +0000 +++ knxd-0.14.69/systemd/knxd.conf 2024-12-16 15:40:26.000000000 +0000 @@ -11,8 +11,10 @@ # multicast client (-b ip:). # knxd's own bus address is 0.0.1; it will assign 0.0.2…0.0.9 to clients. # The knxd.socket file also tells knxd to listen to -# /run/eib (socket activation via systemd) +# /run/knx (socket activation via systemd) # TCP port 6720 (socket activation via systemd) +# The knxd-net.socket file also tells knxd to listen for KNXnet/ip connection on +# /run/knxnet (socket activation via systemd) # You *need* the -e option. Clients cannot connect without "-E". # You can read knxd's logs with diff -Nru knxd-0.14.54.1/systemd/knxd.service.in knxd-0.14.69/systemd/knxd.service.in --- knxd-0.14.54.1/systemd/knxd.service.in 2020-03-06 14:05:31.000000000 +0000 +++ knxd-0.14.69/systemd/knxd.service.in 2024-12-16 15:40:26.000000000 +0000 @@ -1,7 +1,7 @@ [Unit] Description=KNX Daemon -After=network.target knxd.socket -Requires=knxd.socket +After=network.target knxd.socket knxd-net.socket +Requires=knxd.socket knxd-net.socket [Service] EnvironmentFile=@sysconfdir@/knxd.conf @@ -15,4 +15,4 @@ [Install] WantedBy=multi-user.target network-online.target -Also=knxd.socket +Also=knxd.socket knxd-net.socket diff -Nru knxd-0.14.54.1/systemd/knxd.udev knxd-0.14.69/systemd/knxd.udev --- knxd-0.14.54.1/systemd/knxd.udev 2022-01-03 12:20:10.000000000 +0000 +++ knxd-0.14.69/systemd/knxd.udev 2024-12-16 15:40:26.000000000 +0000 @@ -3,26 +3,59 @@ # Do not modify this file. Instead, create a file named # /etc/udev/rules.d/70-your-knxd.rules # and add your rule there. -# +# (Don't forget the ACTION and SUBSYSTEM guards.) + +SUBSYSTEM!="tty", GOTO="knxd_tty_end" + # TPUART: # Run "udevadm info --attribute-walk /sys/bus/usb/drivers/cdc_acm/*/tty/ttyACM0", find the block with ATTRS{manufacturer}=="busware.de". # You need to replace the 'something' with the USB path of your TPUART interface. # (If you're sure that you'll never have more than one, you might delete that condition instead.) -#ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204b", KERNELS=="something", SYMLINK+="ttyKNX1", OWNER="knxd" +#ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204b", KERNELS=="something", SYMLINK+="ttyKNX1", OWNER="knxd" # -# For a TPUART or BAOS interface on top of the Raspberry Pi, use this: -#ACTION=="add", SUBSYSTEM=="tty", KERNEL=="ttyAMA0", SYMLINK+="ttyKNX1", OWNER="knxd" +# For a TPUART or BAOS interface as a Raspberry Pi HAT, use this: +#pi3 +#KERNEL=="ttyAMA0", SYMLINK+="ttyKNX1", OWNER="knxd" +# +#pi4 +#KERNELS=="107d001000.serial", SYMLINK+="ttyKNX1", OWNER="knxd" +# +#pi5 +#KERNELS=="1f00030000.serial", SYMLINK+="ttyKNX1", OWNER="knxd" +# +# +#boot/firmware/config.txt: +#[all] +#dtparam=uart0=on +#enable_uart=1 +#dtoverlay=disable-bt +#dtoverlay=pi3-disable-bt # -# For USB interfaces, replace the ATTRS with your interface's IDs. +# For USB serial interfaces, replace the ATTRS with your interface's IDs. # You get these from "lsusb". If your interface isn't already in the list # below, please submit a bug so that I can include it. # -#ACTION=="add", SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="dead", ATTRS{idProduct}=="beef", OWNER="knxd" +LABEL="knxd_tty_end" -ACTION!="add", GOTO="knxd_end" +# The rest of this file is intended for USB-HID devices. These are always +# accessed via /dev/usb/XXX/YYY, so we only need to change the ownership. +# Unfortunately, disambiguating these interfaces would have to be +# implemented in knxd. +# SUBSYSTEM!="usb", GOTO="knxd_end" ENV{DEVTYPE}!="usb_device", GOTO="knxd_end" +# If you have an USB interface that's not recognized, take the "ACTION=add" +# line below and replace the ATTRs with your interface's IDs. You get these +# from "lsusb". Also, please submit a bug report so the next release of +# knxd works as-is. +# +# To repeat: Add an edited copy of the next line (without the leading '#' +# of course) to something like /etc/udev/rules.d/70-your-knxd.rules -- +# do not edit this file, it'll be overwritten when you update knxd. +# +#ACTION=="add", SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="dead", ATTRS{idProduct}=="beef", OWNER="knxd" + # Schlaps&Partner: EIB-USB Data Interface [Philips Semiconductors] ATTR{idVendor}=="04cc", ATTR{idProduct}=="0301",OWNER="knxd",MODE="0600" # Siemens AG: KNX/EIB-USB Interface (DIN rail) diff -Nru knxd-0.14.54.1/tools/list_AUTHORS knxd-0.14.69/tools/list_AUTHORS --- knxd-0.14.54.1/tools/list_AUTHORS 2018-04-23 11:45:20.000000000 +0000 +++ knxd-0.14.69/tools/list_AUTHORS 2024-12-16 15:40:26.000000000 +0000 @@ -9,6 +9,6 @@ # .mailmap in the root of this repository. echo 'Alphabetical list of surnames of everyone who ever committed to this repository. -Auto-generated from tools/list_AUTHORS and .mailmap +Auto-generated by tools/list_AUTHORS and .mailmap ' git shortlog -se --all | cut -f2 | sort -u -k2