You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2019/11/09 17:47:44 UTC

[plc4x] branch feature/knxnet-ip updated: - Started implementing an active KNXNet/IP driver

This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch feature/knxnet-ip
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/feature/knxnet-ip by this push:
     new 1edd59f  - Started implementing an active KNXNet/IP driver
1edd59f is described below

commit 1edd59fb64cf58eb84a4cd61d1124738b246fd1b
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Sat Nov 9 18:47:33 2019 +0100

    - Started implementing an active KNXNet/IP driver
---
 plc4j/protocols/driver-bases/udp/pom.xml           |  10 +-
 .../protocol/DatagramUnpackingHandler.java         |  39 ++
 .../resources/protocols/knxnetip/knxnetip.mspec    |  77 +--
 sandbox/pom.xml                                    |   1 +
 .../java/streampipes/bacnetip/BacNetIpAdapter.java |  61 ++-
 sandbox/test-java-knxnetip-driver/pom.xml          |   5 +
 ...siveKnxNetIpDriver.java => KnxNetIpDriver.java} |  27 +-
 ...pPlcConnection.java => KnxNetIpConnection.java} |  31 +-
 .../java/knxnetip/events/KnxGatewayFoundEvent.java |  22 +
 .../knxnetip/protocol/KnxNetIpProtocolLogic.java   | 120 +++++
 ...pProtocol.java => KnxNetIpProtocolPackets.java} |   4 +-
 .../services/org.apache.plc4x.java.spi.PlcDriver   |   2 +-
 .../apache/plc4x/java/knxnetip/ManualKnxNetIp.java |  46 +-
 .../pom.xml                                        |  17 +-
 .../passive}/knxnetip/PassiveKnxNetIpDriver.java   |   6 +-
 .../knxnetip/connection/KnxNetIpFieldHandler.java  |  36 ++
 .../connection/PassiveKnxNetIpPlcConnection.java   |   6 +-
 .../java/passive/knxnetip/model/KnxNetIpField.java |  47 ++
 .../knxnetip/protocol/HelloWorldProtocol.java      |   4 +-
 .../knxnetip/protocol/KnxNetIpProtocol.java        |   8 +-
 .../services/org.apache.plc4x.java.spi.PlcDriver   |   2 +-
 .../org/apache/plc4x/java/knxnetip/IOTest.java     |  79 +++
 .../apache/plc4x/java/knxnetip/KNXNetIpTest.java   |  30 ++
 .../apache/plc4x/java/knxnetip/ManualKnxNetIp.java |  27 +
 .../test/resources/testsuite/KNXNetIPTestsuite.xml | 544 +++++++++++++++++++++
 25 files changed, 1107 insertions(+), 144 deletions(-)

diff --git a/plc4j/protocols/driver-bases/udp/pom.xml b/plc4j/protocols/driver-bases/udp/pom.xml
index c7aa485..0a9c43a 100644
--- a/plc4j/protocols/driver-bases/udp/pom.xml
+++ b/plc4j/protocols/driver-bases/udp/pom.xml
@@ -45,12 +45,20 @@
 
     <dependency>
       <groupId>io.netty</groupId>
-      <artifactId>netty-transport</artifactId>
+      <artifactId>netty-buffer</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec</artifactId>
     </dependency>
     <dependency>
       <groupId>io.netty</groupId>
       <artifactId>netty-common</artifactId>
     </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-transport</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>ch.qos.logback</groupId>
diff --git a/plc4j/protocols/driver-bases/udp/src/main/java/org/apache/plc4x/java/base/connection/protocol/DatagramUnpackingHandler.java b/plc4j/protocols/driver-bases/udp/src/main/java/org/apache/plc4x/java/base/connection/protocol/DatagramUnpackingHandler.java
new file mode 100644
index 0000000..5e45723
--- /dev/null
+++ b/plc4j/protocols/driver-bases/udp/src/main/java/org/apache/plc4x/java/base/connection/protocol/DatagramUnpackingHandler.java
@@ -0,0 +1,39 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.base.connection.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.socket.DatagramPacket;
+import io.netty.handler.codec.MessageToMessageDecoder;
+
+import java.util.List;
+
+/**
+ * Handler to unpack and pass along the ByteBuf objects contained in the DatagramPackets.
+ */
+public class DatagramUnpackingHandler extends MessageToMessageDecoder<DatagramPacket> {
+
+    @Override
+    protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List<Object> out) {
+        final ByteBuf content = msg.content();
+        out.add(content.retain());
+    }
+
+}
diff --git a/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec b/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec
index 3e2d429..b1fa2e8 100644
--- a/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec
+++ b/protocols/knxnetip/src/main/resources/protocols/knxnetip/knxnetip.mspec
@@ -45,7 +45,7 @@
         ]
         ['0x0206' ConnectionResponse
             [simple uint 8 'communicationChannelId']
-            [simple uint 8 'status']
+            [enum   Status 'status']
             [simple HPAIDataEndpoint            'hpaiDataEndpoint']
             [simple ConnectionResponseDataBlock 'connectionResponseDataBlock']
         ]
@@ -56,7 +56,7 @@
         ]
         ['0x0208' ConnectionStateResponse
             [simple uint 8 'communicationChannelId']
-            [simple uint 8 'status']
+            [enum   Status 'status']
         ]
         ['0x0209' DisconnectRequest
             [simple   uint 8 'communicationChannelId']
@@ -65,7 +65,7 @@
         ]
         ['0x020A' DisconnectResponse
             [simple uint 8 'communicationChannelId']
-            [simple uint 8 'status']
+            [enum   Status 'status']
         ]
         ['0x020B' UnknownMessage [uint 16 'totalLength']
             [array int 8 'unknownData' count 'totalLength - 6']
@@ -90,17 +90,17 @@
 ]
 
 [type 'HPAIDiscoveryEndpoint'
-    [implicit uint 8    'structureLength' 'lengthInBytes']
-    [simple   uint 8    'hostProtocolCode']
-    [simple   IPAddress 'ipAddress']
-    [simple   uint 16   'ipPort']
+    [implicit uint 8           'structureLength' 'lengthInBytes']
+    [enum     HostProtocolCode 'hostProtocolCode']
+    [simple   IPAddress        'ipAddress']
+    [simple   uint 16          'ipPort']
 ]
 
 [type 'HPAIControlEndpoint'
-    [implicit uint 8    'structureLength' 'lengthInBytes']
-    [simple   uint 8    'hostProtocolCode']
-    [simple   IPAddress 'ipAddress']
-    [simple   uint 16   'ipPort']
+    [implicit uint 8           'structureLength' 'lengthInBytes']
+    [enum     HostProtocolCode 'hostProtocolCode']
+    [simple   IPAddress        'ipAddress']
+    [simple   uint 16          'ipPort']
 ]
 
 [type 'DIBDeviceInfo'
@@ -110,10 +110,10 @@
     [simple   DeviceStatus 'deviceStatus']
     [simple   KNXAddress   'knxAddress']
     [simple   ProjectInstallationIdentifier 'projectInstallationIdentifier']
-    [array    uint 8       'knxNetIpDeviceSerialNumber' count '6']
+    [array    int 8        'knxNetIpDeviceSerialNumber' count '6']
     [simple   IPAddress    'knxNetIpDeviceMulticastAddress']
     [simple   MACAddress   'knxNetIpDeviceMacAddress']
-    [array    uint 8       'deviceFriendlyName'         count '30']
+    [array    int 8        'deviceFriendlyName'         count '30']
 ]
 
 [type 'DIBSuppSvcFamilies'
@@ -123,10 +123,10 @@
 ]
 
 [type 'HPAIDataEndpoint'
-    [implicit uint 8    'structureLength' 'lengthInBytes']
-    [simple   uint 8    'hostProtocolCode']
-    [simple   IPAddress 'ipAddress']
-    [simple   uint 16   'ipPort']
+    [implicit uint 8           'structureLength' 'lengthInBytes']
+    [enum     HostProtocolCode 'hostProtocolCode']
+    [simple   IPAddress        'ipAddress']
+    [simple   uint 16          'ipPort']
 ]
 
 [discriminatedType 'ConnectionRequestInformation'
@@ -136,7 +136,7 @@
         ['0x03' ConnectionRequestInformationDeviceManagement
         ]
         ['0x04' ConnectionRequestInformationTunnelConnection
-            [simple   uint 8    'knxLayer']
+            [enum     KnxLayer  'knxLayer']
             [reserved uint 8    '0x00']
         ]
     ]
@@ -165,7 +165,7 @@
     [implicit uint 8 'structureLength' 'lengthInBytes']
     [simple   uint 8 'communicationChannelId']
     [simple   uint 8 'sequenceCounter']
-    [simple   uint 8 'status']
+    [enum     Status 'status']
 ]
 
 [type 'TunnelingRequestDataBlock'
@@ -179,15 +179,15 @@
     [implicit uint 8 'structureLength' 'lengthInBytes']
     [simple   uint 8 'communicationChannelId']
     [simple   uint 8 'sequenceCounter']
-    [simple   uint 8 'status']
+    [enum     Status 'status']
 ]
 
 [type 'IPAddress'
-    [array uint 8 'addr' count '4']
+    [array int 8 'addr' count '4']
 ]
 
 [type 'MACAddress'
-    [array uint 8 'addr' count '6']
+    [array int 8 'addr' count '6']
 ]
 
 [type 'KNXAddress'
@@ -233,29 +233,28 @@
 [discriminatedType 'CEMI' [uint 8 'size']
     [discriminator uint 8 'messageCode']
     [typeSwitch 'messageCode'
-        ['0x10' CEMILRawReq
+        ['0x10' CEMIRawReq
         ]
-        ['0x11' CEMILDataReq
+        ['0x11' CEMIDataReq
         ]
-        ['0x13' CEMILPollDataReq
+        ['0x13' CEMIPollDataReq
         ]
 
-        ['0x25' CEMILPollDataCon
+        ['0x25' CEMIPollDataCon
         ]
-        ['0x29' CEMILDataInd
+        ['0x29' CEMIDataInd
         ]
-        ['0x2B' CEMILBusmonInd
+        ['0x2B' CEMIBusmonInd
             [simple uint 8                    'additionalInformationLength']
             [array  CEMIAdditionalInformation 'additionalInformation' length 'additionalInformationLength']
             [simple CEMIFrame                 'cemiFrame']
         ]
-        ['0x2D' CEMILRawInd
+        ['0x2D' CEMIRawInd
         ]
-        ['0x2E' CEMILDataCon
+        ['0x2E' CEMIDataCon
         ]
-        ['0x2F' CEMILRawCon
+        ['0x2F' CEMIRawCon
         ]
-
         ['0xFC' CEMIMPropReadReq
             [simple uint 16 'interfaceObjectType']
             [simple uint  8 'objectInstance']
@@ -348,3 +347,17 @@
     ['0x3' LOW]
 ]
 
+[enum uint 8 'Status'
+    ['0x00' NO_ERROR]
+    ['0x24' NO_MORE_CONNECTIONS]
+]
+
+[enum uint 8 'HostProtocolCode'
+    ['0x01' IPV4_UDP]
+    ['0x02' IPV4_TCP]
+]
+
+[enum uint 8 'KnxLayer'
+   ['0x80' TUNNEL_BUSMONITOR]
+]
+
diff --git a/sandbox/pom.xml b/sandbox/pom.xml
index 600d99c..916d160 100644
--- a/sandbox/pom.xml
+++ b/sandbox/pom.xml
@@ -41,6 +41,7 @@
 
     <module>test-java-bacnetip-driver</module>
     <module>test-java-knxnetip-driver</module>
+    <module>test-java-passive-knxnetip-driver</module>
     <module>test-java-s7-driver</module>
     <module>test-java-passive-s7-driver</module>
     <module>test-java-df1-driver</module>
diff --git a/sandbox/streampipes-connectors/src/main/java/org/apache/plc4x/java/streampipes/bacnetip/BacNetIpAdapter.java b/sandbox/streampipes-connectors/src/main/java/org/apache/plc4x/java/streampipes/bacnetip/BacNetIpAdapter.java
index c2c6cbd..c053d77 100644
--- a/sandbox/streampipes-connectors/src/main/java/org/apache/plc4x/java/streampipes/bacnetip/BacNetIpAdapter.java
+++ b/sandbox/streampipes-connectors/src/main/java/org/apache/plc4x/java/streampipes/bacnetip/BacNetIpAdapter.java
@@ -24,13 +24,14 @@ import org.apache.plc4x.java.bacnetip.PassiveBacNetIpDriver;
 import org.apache.plc4x.java.bacnetip.connection.PassiveBacNetIpPlcConnection;
 import org.apache.plc4x.java.bacnetip.readwrite.*;
 import org.apache.plc4x.java.base.PlcMessageToMessageCodec;
+import org.apache.plc4x.java.base.connection.ChannelFactory;
 import org.apache.plc4x.java.base.connection.NettyPlcConnection;
 import org.apache.plc4x.java.base.connection.PcapChannelFactory;
+import org.apache.plc4x.java.base.connection.RawSocketChannelFactory;
 import org.apache.plc4x.java.base.messages.PlcRequestContainer;
 import org.apache.plc4x.java.streampipes.bacnetip.config.ConnectWorkerConfig;
 import org.apache.plc4x.java.utils.pcapsockets.netty.PcapSocketAddress;
 import org.apache.plc4x.java.utils.pcapsockets.netty.PcapSocketChannelConfig;
-import org.apache.plc4x.java.utils.pcapsockets.netty.UdpIpPacketHandler;
 import org.pcap4j.core.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,6 +39,7 @@ import org.streampipes.connect.adapter.Adapter;
 import org.streampipes.connect.adapter.exception.AdapterException;
 import org.streampipes.connect.adapter.exception.ParseException;
 import org.streampipes.connect.adapter.model.specific.SpecificDataStreamAdapter;
+import org.streampipes.connect.adapter.sdk.ParameterExtractor;
 import org.streampipes.connect.container.worker.init.AdapterWorkerContainer;
 import org.streampipes.connect.init.AdapterDeclarerSingleton;
 import org.streampipes.model.AdapterType;
@@ -45,7 +47,7 @@ import org.streampipes.model.connect.adapter.SpecificAdapterStreamDescription;
 import org.streampipes.model.connect.guess.GuessSchema;
 import org.streampipes.model.schema.EventProperty;
 import org.streampipes.model.schema.EventSchema;
-import org.streampipes.model.staticproperty.FileStaticProperty;
+import org.streampipes.model.staticproperty.*;
 import org.streampipes.sdk.StaticProperties;
 import org.streampipes.sdk.builder.PrimitivePropertyBuilder;
 import org.streampipes.sdk.builder.adapter.SpecificDataStreamAdapterBuilder;
@@ -62,14 +64,18 @@ public class BacNetIpAdapter extends SpecificDataStreamAdapter {
 
     private static final Logger logger = LoggerFactory.getLogger(BacNetIpAdapter.class);
 
+    private String deviceName;
+    private String pcapFile;
     private NettyPlcConnection connection;
 
     public BacNetIpAdapter() {
         super();
     }
 
-    public BacNetIpAdapter(SpecificAdapterStreamDescription adapterDescription) {
+    public BacNetIpAdapter(SpecificAdapterStreamDescription adapterDescription, String deviceName, String pcapFile) {
         super(adapterDescription);
+        this.deviceName = deviceName;
+        this.pcapFile = pcapFile;
     }
 
     @Override
@@ -102,12 +108,10 @@ public class BacNetIpAdapter extends SpecificDataStreamAdapter {
             .category(AdapterType.Manufacturing)
             .requiredAlternatives(Labels.from("source", "Source", "Select the source, where the data is read from"),
                 Alternatives.from(Labels.from("device", "Network", "Capture data via network device"),
-                    StaticProperties.group(Labels.withId("device-group"),
-                        StaticProperties.singleValueSelection(Labels.from("network-device", "Network Device", "Network device used for capturing"),
-                            Options.from(deviceList)))),
+                    StaticProperties.singleValueSelection(Labels.from("network-device", "Network Device", "Network device used for capturing"),
+                        Options.from(deviceList))),
                 Alternatives.from(Labels.from("file", "File", "Capture data from a PCAP network recording"),
-                    StaticProperties.group(Labels.withId("file-group"),
-                        new FileStaticProperty(fileLabel.getInternalId(), fileLabel.getLabel(), fileLabel.getDescription()))))
+                    new FileStaticProperty(fileLabel.getInternalId(), fileLabel.getLabel(), fileLabel.getDescription())))
             .build();
         description.setAppId(ID);
         return description;
@@ -186,11 +190,21 @@ public class BacNetIpAdapter extends SpecificDataStreamAdapter {
     @Override
     public void startAdapter() throws AdapterException {
         try {
-            connection = new PassiveBacNetIpPlcConnection(new PcapChannelFactory(
-                //new File("/Users/christofer.dutz/Projects/Apache/PLC4X-Documents/BacNET/Captures/Merck/BACnetWhoIsRouterToNetwork.pcapng"), null,
-                new File("/Users/christofer.dutz/Projects/Apache/PLC4X-Documents/BacNET/Captures/Merck/BACnet.pcapng"), null,
-                PassiveBacNetIpDriver.BACNET_IP_PORT, PcapSocketAddress.ALL_PROTOCOLS,
-                PcapSocketChannelConfig.SPEED_REALTIME, new UdpIpPacketHandler()), "",
+            ChannelFactory channelFactory;
+            if(deviceName != null) {
+                channelFactory = new RawSocketChannelFactory(deviceName, null,
+                    PassiveBacNetIpDriver.BACNET_IP_PORT, PcapSocketAddress.ALL_PROTOCOLS,
+                    new org.apache.plc4x.java.utils.rawsockets.netty.UdpIpPacketHandler());
+            } else if(pcapFile != null) {
+                channelFactory = new PcapChannelFactory(new File(pcapFile), null,
+                    PassiveBacNetIpDriver.BACNET_IP_PORT, PcapSocketAddress.ALL_PROTOCOLS,
+                    PcapSocketChannelConfig.SPEED_REALTIME,
+                    new org.apache.plc4x.java.utils.pcapsockets.netty.UdpIpPacketHandler());
+            } else {
+                throw new AdapterException("Configuration Exception. Either device or file have to be selected.");
+            }
+
+            connection = new PassiveBacNetIpPlcConnection(channelFactory, "",
                 new PlcMessageToMessageCodec<BVLC, PlcRequestContainer>() {
 
                 @Override
@@ -346,8 +360,27 @@ public class BacNetIpAdapter extends SpecificDataStreamAdapter {
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public Adapter getInstance(SpecificAdapterStreamDescription specificAdapterStreamDescription) {
-        return new BacNetIpAdapter(specificAdapterStreamDescription);
+        ParameterExtractor extractor = new ParameterExtractor(specificAdapterStreamDescription.getConfig());
+        String deviceName = null;
+        String pcapFile = null;
+
+        StaticPropertyAlternatives sources = (StaticPropertyAlternatives) extractor.getStaticPropertyByName("source");
+        final Optional<StaticPropertyAlternative> selectedAlternative = sources.getAlternatives().stream().filter(
+            staticPropertyAlternative -> staticPropertyAlternative.getSelected()).findFirst();
+        if(selectedAlternative.isPresent()) {
+            final StaticPropertyAlternative staticPropertyAlternative = selectedAlternative.get();
+            if("device".equals(staticPropertyAlternative.getInternalName())) {
+                final Optional<Option> first =
+                    ((OneOfStaticProperty) staticPropertyAlternative.getStaticProperty()).getOptions().stream().filter(
+                        option -> option.isSelected()).findFirst();
+                deviceName = first.get().getName();
+            } else {
+                pcapFile = ((FileStaticProperty) staticPropertyAlternative.getStaticProperty()).getLocationPath();
+            }
+        }
+        return new BacNetIpAdapter(specificAdapterStreamDescription, deviceName, pcapFile);
     }
 
     @Override
diff --git a/sandbox/test-java-knxnetip-driver/pom.xml b/sandbox/test-java-knxnetip-driver/pom.xml
index 3b3bec4..735b440 100644
--- a/sandbox/test-java-knxnetip-driver/pom.xml
+++ b/sandbox/test-java-knxnetip-driver/pom.xml
@@ -71,6 +71,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-protocol-driver-base-udp</artifactId>
+      <version>0.6.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
       <artifactId>plc4j-protocol-driver-base-raw-socket</artifactId>
       <version>0.6.0-SNAPSHOT</version>
     </dependency>
diff --git a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/PassiveKnxNetIpDriver.java b/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java
similarity index 69%
copy from sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/PassiveKnxNetIpDriver.java
copy to sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java
index 1f17192..d5d5d88 100644
--- a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/PassiveKnxNetIpDriver.java
+++ b/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/KnxNetIpDriver.java
@@ -21,31 +21,27 @@ package org.apache.plc4x.java.knxnetip;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.authentication.PlcAuthentication;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.knxnetip.connection.PassiveKnxNetIpPlcConnection;
-import org.apache.plc4x.java.knxnetip.protocol.HelloWorldProtocol;
+import org.apache.plc4x.java.knxnetip.connection.KnxNetIpConnection;
+import org.apache.plc4x.java.knxnetip.protocol.KnxNetIpProtocolLogic;
 import org.apache.plc4x.java.spi.PlcDriver;
-import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketIpAddress;
 
+import java.net.InetAddress;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static org.apache.plc4x.java.utils.rawsockets.netty.RawSocketAddress.ALL_PROTOCOLS;
-
-public class PassiveKnxNetIpDriver implements PlcDriver {
-
-    public static final int KNXNET_IP_PORT = 3671;
+public class KnxNetIpDriver implements PlcDriver {
 
     private static final Pattern PASSIVE_KNXNET_IP_URI_PATTERN =
-        Pattern.compile("^knxnet-ip-passive://(?<networkDevice>.*)(?<params>\\?.*)?");
+        Pattern.compile("^knxnet-ip://(?<host>.*)(?<params>\\?.*)?");
 
     @Override
     public String getProtocolCode() {
-        return "knxnet-ip-passive";
+        return "knxnet-ip";
     }
 
     @Override
     public String getProtocolName() {
-        return "KNXNet/IP (Passive)";
+        return "KNXNet/IP";
     }
 
     @Override
@@ -53,16 +49,15 @@ public class PassiveKnxNetIpDriver implements PlcDriver {
         Matcher matcher = PASSIVE_KNXNET_IP_URI_PATTERN.matcher(url);
         if (!matcher.matches()) {
             throw new PlcConnectionException(
-                "Connection url doesn't match the format 'knxnet-ip-passive://{host|ip}'");
+                "Connection url doesn't match the format 'knxnet-ip://{host|ip}'");
         }
-        String networkDevice = matcher.group("networkDevice");
+        String host = matcher.group("host");
 
         String params = matcher.group("params") != null ? matcher.group("params").substring(1) : null;
 
         try {
-            RawSocketIpAddress rawSocketAddress = new RawSocketIpAddress(
-                networkDevice, ALL_PROTOCOLS, null, KNXNET_IP_PORT);
-            return new PassiveKnxNetIpPlcConnection(rawSocketAddress, params, new HelloWorldProtocol());
+            InetAddress serverInetAddress = InetAddress.getByName(host);
+            return new KnxNetIpConnection(serverInetAddress, params, new KnxNetIpProtocolLogic());
         } catch (Exception e) {
             throw new PlcConnectionException("Error connecting to host", e);
         }
diff --git a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/connection/PassiveKnxNetIpPlcConnection.java b/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/connection/KnxNetIpConnection.java
similarity index 77%
copy from sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/connection/PassiveKnxNetIpPlcConnection.java
copy to sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/connection/KnxNetIpConnection.java
index e82c7df..91eca9e 100644
--- a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/connection/PassiveKnxNetIpPlcConnection.java
+++ b/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/connection/KnxNetIpConnection.java
@@ -25,39 +25,40 @@ import org.apache.plc4x.java.api.messages.PlcReadResponse;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.base.connection.ChannelFactory;
 import org.apache.plc4x.java.base.connection.NettyPlcConnection;
-import org.apache.plc4x.java.base.connection.RawSocketChannelFactory;
+import org.apache.plc4x.java.base.connection.UdpSocketChannelFactory;
+import org.apache.plc4x.java.base.connection.protocol.DatagramUnpackingHandler;
+import org.apache.plc4x.java.base.events.ConnectEvent;
 import org.apache.plc4x.java.base.events.ConnectedEvent;
 import org.apache.plc4x.java.base.messages.*;
 import org.apache.plc4x.java.knxnetip.model.KnxNetIpField;
-import org.apache.plc4x.java.knxnetip.protocol.KnxNetIpProtocol;
-import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketAddress;
-import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketIpAddress;
-import org.apache.plc4x.java.utils.rawsockets.netty.UdpIpPacketHandler;
+import org.apache.plc4x.java.knxnetip.protocol.KnxNetIpProtocolPackets;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.net.InetAddress;
 import java.util.concurrent.CompletableFuture;
 
-public class PassiveKnxNetIpPlcConnection extends NettyPlcConnection implements PlcReader {
+public class KnxNetIpConnection extends NettyPlcConnection implements PlcReader {
 
-    private static final Logger logger = LoggerFactory.getLogger(PassiveKnxNetIpPlcConnection.class);
+    public static final int KNXNET_IP_PORT = 3671;
+
+    private static final Logger logger = LoggerFactory.getLogger(KnxNetIpConnection.class);
 
     private final ChannelHandler handler;
 
-    public PassiveKnxNetIpPlcConnection(RawSocketIpAddress address, String params, ChannelHandler handler) {
-        this(new RawSocketChannelFactory(address.getDeviceName(), null,
-            address.getPort(), RawSocketAddress.ALL_PROTOCOLS, new UdpIpPacketHandler()), params, handler);
+    public KnxNetIpConnection(InetAddress address, String params, ChannelHandler handler) {
+        this(new UdpSocketChannelFactory(address, KNXNET_IP_PORT), params, handler);
     }
 
-    public PassiveKnxNetIpPlcConnection(ChannelFactory channelFactory, String params, ChannelHandler handler) {
+    public KnxNetIpConnection(ChannelFactory channelFactory, String params, ChannelHandler handler) {
         super(channelFactory, true);
         this.handler = handler;
     }
 
     @Override
     protected void sendChannelCreatedEvent() {
-        // As this type of protocol doesn't require any form of connection, we just send the connected event.
-        channel.pipeline().fireUserEventTriggered(new ConnectedEvent());
+        // Send an event to the pipeline telling the Protocol filters what's going on.
+        channel.pipeline().fireUserEventTriggered(new ConnectEvent());
     }
 
     @Override
@@ -82,7 +83,9 @@ public class PassiveKnxNetIpPlcConnection extends NettyPlcConnection implements
                         }
                     }
                 });
-                pipeline.addLast(new KnxNetIpProtocol());
+                // Unpack the ByteBuf included in the DatagramPackage.
+                pipeline.addLast(new DatagramUnpackingHandler());
+                pipeline.addLast(new KnxNetIpProtocolPackets());
                 pipeline.addLast(handler);
             }
         };
diff --git a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/events/KnxGatewayFoundEvent.java b/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/events/KnxGatewayFoundEvent.java
new file mode 100644
index 0000000..3b73148
--- /dev/null
+++ b/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/events/KnxGatewayFoundEvent.java
@@ -0,0 +1,22 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.knxnetip.events;
+
+public class KnxGatewayFoundEvent {
+}
diff --git a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java b/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
new file mode 100644
index 0000000..bfee8d1
--- /dev/null
+++ b/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
@@ -0,0 +1,120 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.knxnetip.protocol;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.socket.DatagramChannel;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.plc4x.java.base.PlcMessageToMessageCodec;
+import org.apache.plc4x.java.base.events.ConnectEvent;
+import org.apache.plc4x.java.base.events.ConnectedEvent;
+import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.java.knxnetip.events.KnxGatewayFoundEvent;
+import org.apache.plc4x.java.knxnetip.readwrite.*;
+import org.apache.plc4x.java.knxnetip.readwrite.types.HostProtocolCode;
+import org.apache.plc4x.java.knxnetip.readwrite.types.KnxLayer;
+import org.apache.plc4x.java.knxnetip.readwrite.types.Status;
+
+import java.net.InetSocketAddress;
+import java.util.Arrays;
+import java.util.List;
+
+public class KnxNetIpProtocolLogic extends PlcMessageToMessageCodec<KNXNetIPMessage, PlcRequestContainer> {
+
+    private KNXAddress gatewayAddress;
+    private String gatewayName;
+
+    @Override
+    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+        if (evt instanceof ConnectEvent) {
+            DatagramChannel channel = (DatagramChannel) ctx.pipeline().channel();
+            final InetSocketAddress localSocketAddress = channel.localAddress();
+            final IPAddress localAddress = new IPAddress(localSocketAddress.getAddress().getAddress());
+            final int localPort = localSocketAddress.getPort();
+            SearchRequest searchRequest = new SearchRequest(new HPAIDiscoveryEndpoint(HostProtocolCode.IPV4_UDP, localAddress, localPort));
+            ctx.channel().writeAndFlush(searchRequest);
+        } else if(evt instanceof KnxGatewayFoundEvent) {
+            DatagramChannel channel = (DatagramChannel) ctx.pipeline().channel();
+            final InetSocketAddress localSocketAddress = channel.localAddress();
+            final IPAddress localAddress = new IPAddress(localSocketAddress.getAddress().getAddress());
+            final int localPort = localSocketAddress.getPort();
+            ConnectionRequest connectionRequest = new ConnectionRequest(
+                new HPAIDiscoveryEndpoint(HostProtocolCode.IPV4_UDP, localAddress, localPort),
+                new HPAIDataEndpoint(HostProtocolCode.IPV4_UDP, localAddress, localPort),
+                new ConnectionRequestInformationTunnelConnection(KnxLayer.TUNNEL_BUSMONITOR));
+            ctx.channel().writeAndFlush(connectionRequest);
+        }
+    }
+
+    @Override
+    protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List<Object> out) {
+        // Ignore ...
+    }
+
+    @Override
+    protected void decode(ChannelHandlerContext ctx, KNXNetIPMessage msg, List<Object> out) {
+        if(msg instanceof SearchResponse) {
+            SearchResponse searchResponse = (SearchResponse) msg;
+            final ServiceId tunnelingService = Arrays.stream(searchResponse.getDibSuppSvcFamilies().getServiceIds()).filter(serviceId -> serviceId instanceof KnxNetIpTunneling).findFirst().orElse(null);
+            // If this service has the
+            if(tunnelingService != null) {
+                gatewayAddress = searchResponse.getDibDeviceInfo().getKnxAddress();
+                gatewayName = new String(searchResponse.getDibDeviceInfo().getDeviceFriendlyName());
+                ctx.channel().pipeline().fireUserEventTriggered(new KnxGatewayFoundEvent());
+            }
+        } else if(msg instanceof ConnectionResponse) {
+            ConnectionResponse connectionResponse = (ConnectionResponse) msg;
+            Status status = connectionResponse.getStatus();
+            if(status == Status.NO_ERROR) {
+                ctx.channel().pipeline().fireUserEventTriggered(new ConnectedEvent());
+            }
+        } else if(msg instanceof TunnelingRequest) {
+            TunnelingRequest tunnelingRequest = (TunnelingRequest) msg;
+            final short communicationChannelId = tunnelingRequest.getTunnelingRequestDataBlock().getCommunicationChannelId();
+            final short sequenceCounter = tunnelingRequest.getTunnelingRequestDataBlock().getSequenceCounter();
+            TunnelingResponse tunnelingResponse = new TunnelingResponse(
+                new TunnelingResponseDataBlock(communicationChannelId, sequenceCounter, Status.NO_ERROR));
+            ctx.channel().writeAndFlush(tunnelingResponse);
+            CEMIBusmonInd busmonInd = (CEMIBusmonInd) tunnelingRequest.getCemi();
+            if(busmonInd.getCemiFrame() instanceof CEMIFrameData) {
+                outputStringRepresentation((CEMIFrameData) busmonInd.getCemiFrame());
+            }
+        }
+    }
+
+    private void outputStringRepresentation(CEMIFrameData data) {
+        final CEMIAddress sourceAddress = data.getSourceAddress();
+        final CEMIAddress destinationAddress = data.getDestinationAddress();
+        final boolean groupAddress = data.getGroupAddress();
+        final byte[] payload = data.getData();
+        String payloadString = Hex.encodeHexString(payload);
+        if(groupAddress) {
+            System.out.println(String.format("Telegram from %d.%d.%d to %d/%d/%d with payload %s",
+                sourceAddress.getArea(), sourceAddress.getLine(), sourceAddress.getDevice(),
+                destinationAddress.getArea(), destinationAddress.getLine(), destinationAddress.getDevice(),
+                payloadString));
+        } else {
+            System.out.println(String.format("Telegram from %d.%d.%d to %d.%d.%d with payload %s",
+                sourceAddress.getArea(), sourceAddress.getLine(), sourceAddress.getDevice(),
+                destinationAddress.getArea(), destinationAddress.getLine(), destinationAddress.getDevice(),
+                payloadString));
+        }
+    }
+
+}
diff --git a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocol.java b/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolPackets.java
similarity index 93%
copy from sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocol.java
copy to sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolPackets.java
index d8e5cc9..4b60b4b 100644
--- a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocol.java
+++ b/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolPackets.java
@@ -27,9 +27,9 @@ import org.apache.plc4x.java.utils.ParseException;
 import org.apache.plc4x.java.utils.ReadBuffer;
 import org.apache.plc4x.java.utils.WriteBuffer;
 
-public class KnxNetIpProtocol extends GeneratedDriverByteToMessageCodec<KNXNetIPMessage> {
+public class KnxNetIpProtocolPackets extends GeneratedDriverByteToMessageCodec<KNXNetIPMessage> {
 
-    public KnxNetIpProtocol() {
+    public KnxNetIpProtocolPackets() {
         super(new MessageIO<KNXNetIPMessage, KNXNetIPMessage>() {
             @Override
             public KNXNetIPMessage parse(ReadBuffer io) throws ParseException {
diff --git a/sandbox/test-java-knxnetip-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver b/sandbox/test-java-knxnetip-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
index afe85bf..50a5f8d 100644
--- a/sandbox/test-java-knxnetip-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
+++ b/sandbox/test-java-knxnetip-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
@@ -16,4 +16,4 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-org.apache.plc4x.java.knxnetip.PassiveKnxNetIpDriver
+org.apache.plc4x.java.knxnetip.KnxNetIpDriver
diff --git a/sandbox/test-java-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java b/sandbox/test-java-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java
index a1ac874..76d89db 100644
--- a/sandbox/test-java-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java
+++ b/sandbox/test-java-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java
@@ -18,52 +18,14 @@ under the License.
 */
 package org.apache.plc4x.java.knxnetip;
 
-import io.netty.channel.ChannelHandlerContext;
-import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.base.PlcMessageToMessageCodec;
-import org.apache.plc4x.java.base.connection.NettyPlcConnection;
-import org.apache.plc4x.java.base.connection.PcapChannelFactory;
-import org.apache.plc4x.java.base.messages.PlcRequestContainer;
-import org.apache.plc4x.java.knxnetip.connection.PassiveKnxNetIpPlcConnection;
-import org.apache.plc4x.java.knxnetip.readwrite.KNXNetIPMessage;
-import org.apache.plc4x.java.utils.pcapsockets.netty.PcapSocketAddress;
-import org.apache.plc4x.java.utils.pcapsockets.netty.PcapSocketChannelConfig;
-import org.apache.plc4x.java.utils.pcapsockets.netty.UdpIpPacketHandler;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.util.List;
+import org.apache.plc4x.java.PlcDriverManager;
+import org.apache.plc4x.java.api.PlcConnection;
 
 public class ManualKnxNetIp {
 
-    private static final Logger logger = LoggerFactory.getLogger(ManualKnxNetIp.class);
-
-    private static NettyPlcConnection connection;
-
     public static void main(String[] args) throws Exception {
-        try {
-            connection = new PassiveKnxNetIpPlcConnection(new PcapChannelFactory(
-                new File(args[0]), null,
-                PassiveKnxNetIpDriver.KNXNET_IP_PORT, PcapSocketAddress.ALL_PROTOCOLS,
-                PcapSocketChannelConfig.SPEED_REALTIME, new UdpIpPacketHandler()), "",
-                new PlcMessageToMessageCodec<KNXNetIPMessage, PlcRequestContainer>() {
-
-                    @Override
-                    protected void decode(ChannelHandlerContext channelHandlerContext, KNXNetIPMessage packet, List<Object> list) throws Exception {
-                        System.out.println(packet);
-                    }
-
-                    @Override
-                    protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List<Object> out) throws Exception {
-                        // Ignore this as we don't send anything.
-                    }
-                });
-            connection.connect();
-        } catch (PlcConnectionException e) {
-            logger.error("An error occurred starting the BACnet/IP driver", e);
-            throw new Exception(e);
-        }
+        final PlcConnection connection = new PlcDriverManager().getConnection("knxnet-ip://192.168.42.11");
+        System.out.println(connection);
     }
 
 }
diff --git a/sandbox/test-java-knxnetip-driver/pom.xml b/sandbox/test-java-passive-knxnetip-driver/pom.xml
similarity index 93%
copy from sandbox/test-java-knxnetip-driver/pom.xml
copy to sandbox/test-java-passive-knxnetip-driver/pom.xml
index 3b3bec4..ca9ac14 100644
--- a/sandbox/test-java-knxnetip-driver/pom.xml
+++ b/sandbox/test-java-passive-knxnetip-driver/pom.xml
@@ -26,9 +26,9 @@
     <version>0.6.0-SNAPSHOT</version>
   </parent>
 
-  <artifactId>test-java-knxnetip-driver</artifactId>
+  <artifactId>test-java-passive-knxnetip-driver</artifactId>
 
-  <name>Sandbox: Test Generated KNXNet/IP Driver</name>
+  <name>Sandbox: Test Generated KNXNet/IP Driver (Passive)</name>
 
   <build>
     <plugins>
@@ -45,7 +45,7 @@
             <configuration>
               <protocolName>knxnetip</protocolName>
               <languageName>java</languageName>
-              <outputFlavor>read-write</outputFlavor>
+              <outputFlavor>passive</outputFlavor>
             </configuration>
           </execution>
         </executions>
@@ -74,6 +74,11 @@
       <artifactId>plc4j-protocol-driver-base-raw-socket</artifactId>
       <version>0.6.0-SNAPSHOT</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-utils-raw-sockets</artifactId>
+      <version>0.6.0-SNAPSHOT</version>
+    </dependency>
 
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
@@ -87,12 +92,6 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.apache.plc4x</groupId>
-      <artifactId>plc4j-protocol-driver-base-pcap-socket</artifactId>
-      <version>0.6.0-SNAPSHOT</version>
-      <!--scope>test</scope-->
-    </dependency>
-    <dependency>
       <groupId>ch.qos.logback</groupId>
       <artifactId>logback-classic</artifactId>
       <scope>test</scope>
diff --git a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/PassiveKnxNetIpDriver.java b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/PassiveKnxNetIpDriver.java
similarity index 93%
rename from sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/PassiveKnxNetIpDriver.java
rename to sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/PassiveKnxNetIpDriver.java
index 1f17192..28225f9 100644
--- a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/PassiveKnxNetIpDriver.java
+++ b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/PassiveKnxNetIpDriver.java
@@ -16,13 +16,13 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.knxnetip;
+package org.apache.plc4x.java.passive.knxnetip;
 
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.authentication.PlcAuthentication;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.knxnetip.connection.PassiveKnxNetIpPlcConnection;
-import org.apache.plc4x.java.knxnetip.protocol.HelloWorldProtocol;
+import org.apache.plc4x.java.passive.knxnetip.connection.PassiveKnxNetIpPlcConnection;
+import org.apache.plc4x.java.passive.knxnetip.protocol.HelloWorldProtocol;
 import org.apache.plc4x.java.spi.PlcDriver;
 import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketIpAddress;
 
diff --git a/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/connection/KnxNetIpFieldHandler.java b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/connection/KnxNetIpFieldHandler.java
new file mode 100644
index 0000000..5787d10
--- /dev/null
+++ b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/connection/KnxNetIpFieldHandler.java
@@ -0,0 +1,36 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.passive.knxnetip.connection;
+
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.base.connection.DefaultPlcFieldHandler;
+import org.apache.plc4x.java.passive.knxnetip.model.KnxNetIpField;
+
+public class KnxNetIpFieldHandler extends DefaultPlcFieldHandler {
+
+    @Override
+    public PlcField createField(String fieldQuery) throws PlcInvalidFieldException {
+        if (KnxNetIpField.matches(fieldQuery)) {
+            return KnxNetIpField.of(fieldQuery);
+        }
+        throw new PlcInvalidFieldException(fieldQuery);
+    }
+
+}
diff --git a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/connection/PassiveKnxNetIpPlcConnection.java b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/connection/PassiveKnxNetIpPlcConnection.java
similarity index 95%
rename from sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/connection/PassiveKnxNetIpPlcConnection.java
rename to sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/connection/PassiveKnxNetIpPlcConnection.java
index e82c7df..cca1a3c 100644
--- a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/connection/PassiveKnxNetIpPlcConnection.java
+++ b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/connection/PassiveKnxNetIpPlcConnection.java
@@ -16,7 +16,7 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.knxnetip.connection;
+package org.apache.plc4x.java.passive.knxnetip.connection;
 
 import io.netty.channel.*;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
@@ -28,8 +28,8 @@ import org.apache.plc4x.java.base.connection.NettyPlcConnection;
 import org.apache.plc4x.java.base.connection.RawSocketChannelFactory;
 import org.apache.plc4x.java.base.events.ConnectedEvent;
 import org.apache.plc4x.java.base.messages.*;
-import org.apache.plc4x.java.knxnetip.model.KnxNetIpField;
-import org.apache.plc4x.java.knxnetip.protocol.KnxNetIpProtocol;
+import org.apache.plc4x.java.passive.knxnetip.model.KnxNetIpField;
+import org.apache.plc4x.java.passive.knxnetip.protocol.KnxNetIpProtocol;
 import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketAddress;
 import org.apache.plc4x.java.utils.rawsockets.netty.RawSocketIpAddress;
 import org.apache.plc4x.java.utils.rawsockets.netty.UdpIpPacketHandler;
diff --git a/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/model/KnxNetIpField.java b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/model/KnxNetIpField.java
new file mode 100644
index 0000000..b7e45a5
--- /dev/null
+++ b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/model/KnxNetIpField.java
@@ -0,0 +1,47 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.passive.knxnetip.model;
+
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.apache.plc4x.java.api.model.PlcField;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class KnxNetIpField implements PlcField {
+
+    private static final Pattern ADDRESS_PATTERN =
+        Pattern.compile("^N(?<fileNumber>\\d{1,7}):(?<elementNumber>\\d{1,7})(/(?<bitNumber>\\d{1,7}))?:(?<dataType>[a-zA-Z_]+)(\\[(?<size>\\d+)])?");
+
+    public KnxNetIpField() {
+    }
+
+    public static boolean matches(String fieldString) {
+        return ADDRESS_PATTERN.matcher(fieldString).matches();
+    }
+
+    public static KnxNetIpField of(String fieldString) {
+        Matcher matcher = ADDRESS_PATTERN.matcher(fieldString);
+        if(matcher.matches()) {
+            return new KnxNetIpField();
+        }
+        throw new PlcInvalidFieldException("Unable to parse address: " + fieldString);
+    }
+
+}
diff --git a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/HelloWorldProtocol.java b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/protocol/HelloWorldProtocol.java
similarity index 96%
rename from sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/HelloWorldProtocol.java
rename to sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/protocol/HelloWorldProtocol.java
index 6bd481a..5c0fb6d 100644
--- a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/HelloWorldProtocol.java
+++ b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/protocol/HelloWorldProtocol.java
@@ -16,12 +16,12 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.knxnetip.protocol;
+package org.apache.plc4x.java.passive.knxnetip.protocol;
 
 import io.netty.channel.ChannelHandlerContext;
 import org.apache.plc4x.java.base.PlcMessageToMessageCodec;
 import org.apache.plc4x.java.base.messages.PlcRequestContainer;
-import org.apache.plc4x.java.knxnetip.readwrite.KNXNetIPMessage;
+import org.apache.plc4x.java.knxnetip.passive.KNXNetIPMessage;
 
 import java.util.List;
 
diff --git a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocol.java b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/protocol/KnxNetIpProtocol.java
similarity index 88%
rename from sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocol.java
rename to sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/protocol/KnxNetIpProtocol.java
index d8e5cc9..9d97bfd 100644
--- a/sandbox/test-java-knxnetip-driver/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocol.java
+++ b/sandbox/test-java-passive-knxnetip-driver/src/main/java/org/apache/plc4x/java/passive/knxnetip/protocol/KnxNetIpProtocol.java
@@ -16,12 +16,12 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.knxnetip.protocol;
+package org.apache.plc4x.java.passive.knxnetip.protocol;
 
 import io.netty.buffer.ByteBuf;
 import org.apache.plc4x.java.base.GeneratedDriverByteToMessageCodec;
-import org.apache.plc4x.java.knxnetip.readwrite.KNXNetIPMessage;
-import org.apache.plc4x.java.knxnetip.readwrite.io.KNXNetIPMessageIO;
+import org.apache.plc4x.java.knxnetip.passive.KNXNetIPMessage;
+import org.apache.plc4x.java.knxnetip.passive.io.KNXNetIPMessageIO;
 import org.apache.plc4x.java.utils.MessageIO;
 import org.apache.plc4x.java.utils.ParseException;
 import org.apache.plc4x.java.utils.ReadBuffer;
@@ -38,7 +38,7 @@ public class KnxNetIpProtocol extends GeneratedDriverByteToMessageCodec<KNXNetIP
 
             @Override
             public void serialize(WriteBuffer io, KNXNetIPMessage value) throws ParseException {
-                KNXNetIPMessageIO.serialize(io, value);
+                // Ignore.
             }
         });
     }
diff --git a/sandbox/test-java-knxnetip-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver b/sandbox/test-java-passive-knxnetip-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
similarity index 92%
copy from sandbox/test-java-knxnetip-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
copy to sandbox/test-java-passive-knxnetip-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
index afe85bf..087e7e6 100644
--- a/sandbox/test-java-knxnetip-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
+++ b/sandbox/test-java-passive-knxnetip-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
@@ -16,4 +16,4 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-org.apache.plc4x.java.knxnetip.PassiveKnxNetIpDriver
+org.apache.plc4x.java.passive.knxnetip.PassiveKnxNetIpDriver
diff --git a/sandbox/test-java-passive-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java b/sandbox/test-java-passive-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java
new file mode 100644
index 0000000..952ff89
--- /dev/null
+++ b/sandbox/test-java-passive-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/IOTest.java
@@ -0,0 +1,79 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+package org.apache.plc4x.java.knxnetip;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.plc4x.java.knxnetip.passive.KNXNetIPMessage;
+import org.apache.plc4x.java.knxnetip.passive.io.KNXNetIPMessageIO;
+import org.apache.plc4x.java.utils.ReadBuffer;
+import org.apache.plc4x.java.utils.WriteBuffer;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+
+public class IOTest {
+
+    @Test
+    public void testXml() throws Exception {
+        byte[] rData = Hex.decodeHex("06100420001c046b00002b0703010504024502bc360a1e0ce100810d");
+        ObjectMapper mapper = new XmlMapper().enableDefaultTyping();
+        ReadBuffer rBuf = new ReadBuffer(rData);
+        KNXNetIPMessage packet = new KNXNetIPMessageIO().parse(rBuf);
+        String xml = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(packet);
+        System.out.println(xml);
+        KNXNetIPMessage pack2 = mapper.readValue(xml, KNXNetIPMessage.class);
+        System.out.println(pack2);
+    }
+
+    @Test
+    public void testJson() throws Exception {
+        byte[] rData = Hex.decodeHex("0610020500180801c0a82a46c4090801c0a82a46c40a0203");
+        ObjectMapper mapper = new ObjectMapper().enableDefaultTyping();
+        ReadBuffer rBuf = new ReadBuffer(rData);
+        KNXNetIPMessage packet = new KNXNetIPMessageIO().parse(rBuf);
+        String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(packet);
+        System.out.println(json);
+        KNXNetIPMessage pack2 = mapper.readValue(json, KNXNetIPMessage.class);
+        System.out.println(pack2);
+    }
+
+    @Test
+    public void testParser() throws Exception {
+        byte[] rData = Hex.decodeHex("0610020500180801c0a82a46c4090801c0a82a46c40a0203");
+        long start = System.currentTimeMillis();
+        int numRunsParse = 20000;
+
+        KNXNetIPMessageIO knxNetIPMessageIO = new KNXNetIPMessageIO();
+
+        // Benchmark the parsing code
+        KNXNetIPMessage packet = null;
+        for(int i = 0; i < numRunsParse; i++) {
+            ReadBuffer rBuf = new ReadBuffer(rData);
+            packet = knxNetIPMessageIO.parse(rBuf);
+        }
+        long endParsing = System.currentTimeMillis();
+
+        System.out.println("Parsed " + numRunsParse + " packets in " + (endParsing - start) + "ms");
+        System.out.println("That's " + ((float) (endParsing - start) / numRunsParse) + "ms per packet");
+    }
+
+}
diff --git a/sandbox/test-java-passive-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/KNXNetIpTest.java b/sandbox/test-java-passive-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/KNXNetIpTest.java
new file mode 100644
index 0000000..b968eeb
--- /dev/null
+++ b/sandbox/test-java-passive-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/KNXNetIpTest.java
@@ -0,0 +1,30 @@
+/*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*/
+
+package org.apache.plc4x.java.knxnetip;
+
+import org.apache.plc4x.protocol.test.ProtocolTestsuiteRunner;
+
+public class KNXNetIpTest extends ProtocolTestsuiteRunner {
+
+    public KNXNetIpTest() {
+        super("/testsuite/KNXNetIPTestsuite.xml");
+    }
+
+}
diff --git a/sandbox/test-java-passive-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java b/sandbox/test-java-passive-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java
new file mode 100644
index 0000000..bc8253b
--- /dev/null
+++ b/sandbox/test-java-passive-knxnetip-driver/src/test/java/org/apache/plc4x/java/knxnetip/ManualKnxNetIp.java
@@ -0,0 +1,27 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.knxnetip;
+
+public class ManualKnxNetIp {
+
+    public static void main(String[] args) {
+
+    }
+
+}
diff --git a/sandbox/test-java-passive-knxnetip-driver/src/test/resources/testsuite/KNXNetIPTestsuite.xml b/sandbox/test-java-passive-knxnetip-driver/src/test/resources/testsuite/KNXNetIPTestsuite.xml
new file mode 100644
index 0000000..10fb85c
--- /dev/null
+++ b/sandbox/test-java-passive-knxnetip-driver/src/test/resources/testsuite/KNXNetIPTestsuite.xml
@@ -0,0 +1,544 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  -->
+<test:testsuite xmlns:test="https://plc4x.apache.org/schemas/testsuite.xsd">
+
+  <name>KNXNet/IP</name>
+
+  <testcase>
+    <name>Search Request</name>
+    <raw>06100201000e0801c0a82a46ef8e</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <SearchRequest className="org.apache.plc4x.java.knxnetip.readwrite.SearchRequest">
+        <hpaiIDiscoveryEndpoint>
+          <hostProtocolCode>1</hostProtocolCode>
+          <ipAddress>
+            <addr>
+              <addr>192</addr>
+              <addr>168</addr>
+              <addr>42</addr>
+              <addr>70</addr>
+            </addr>
+          </ipAddress>
+          <ipPort>61326</ipPort>
+        </hpaiIDiscoveryEndpoint>
+      </SearchRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Search Response</name>
+    <raw>06100202004c0801c0a82a0b0e5736010200ffff000000082d409852e000170c000ab327553647697261204b4e582f49502d5363686e6974747374656c6c6500000000000802020103010401</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <SearchResponse className="org.apache.plc4x.java.knxnetip.readwrite.SearchResponse">
+        <hpaiControlEndpoint>
+          <hostProtocolCode>1</hostProtocolCode>
+          <ipAddress>
+            <addr>
+              <addr>192</addr>
+              <addr>168</addr>
+              <addr>42</addr>
+              <addr>11</addr>
+            </addr>
+          </ipAddress>
+          <ipPort>3671</ipPort>
+        </hpaiControlEndpoint>
+        <dibDeviceInfo>
+          <descriptionType>1</descriptionType>
+          <knxMedium>2</knxMedium>
+          <deviceStatus>
+            <programMode>false</programMode>
+          </deviceStatus>
+          <knxAddress>
+            <mainGroup>15</mainGroup>
+            <middleGroup>15</middleGroup>
+            <subGroup>255</subGroup>
+          </knxAddress>
+          <projectInstallationIdentifier>
+            <projectNumber>0</projectNumber>
+            <installationNumber>0</installationNumber>
+          </projectInstallationIdentifier>
+          <knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>0</knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>8</knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>45</knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>64</knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>152</knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>82</knxNetIpDeviceSerialNumber>
+          </knxNetIpDeviceSerialNumber>
+          <knxNetIpDeviceMulticastAddress>
+            <addr>
+              <addr>224</addr>
+              <addr>0</addr>
+              <addr>23</addr>
+              <addr>12</addr>
+            </addr>
+          </knxNetIpDeviceMulticastAddress>
+          <knxNetIpDeviceMacAddress>
+            <addr>
+              <addr>0</addr>
+              <addr>10</addr>
+              <addr>179</addr>
+              <addr>39</addr>
+              <addr>85</addr>
+              <addr>54</addr>
+            </addr>
+          </knxNetIpDeviceMacAddress>
+          <deviceFriendlyName>
+            <deviceFriendlyName>71</deviceFriendlyName>
+            <deviceFriendlyName>105</deviceFriendlyName>
+            <deviceFriendlyName>114</deviceFriendlyName>
+            <deviceFriendlyName>97</deviceFriendlyName>
+            <deviceFriendlyName>32</deviceFriendlyName>
+            <deviceFriendlyName>75</deviceFriendlyName>
+            <deviceFriendlyName>78</deviceFriendlyName>
+            <deviceFriendlyName>88</deviceFriendlyName>
+            <deviceFriendlyName>47</deviceFriendlyName>
+            <deviceFriendlyName>73</deviceFriendlyName>
+            <deviceFriendlyName>80</deviceFriendlyName>
+            <deviceFriendlyName>45</deviceFriendlyName>
+            <deviceFriendlyName>83</deviceFriendlyName>
+            <deviceFriendlyName>99</deviceFriendlyName>
+            <deviceFriendlyName>104</deviceFriendlyName>
+            <deviceFriendlyName>110</deviceFriendlyName>
+            <deviceFriendlyName>105</deviceFriendlyName>
+            <deviceFriendlyName>116</deviceFriendlyName>
+            <deviceFriendlyName>116</deviceFriendlyName>
+            <deviceFriendlyName>115</deviceFriendlyName>
+            <deviceFriendlyName>116</deviceFriendlyName>
+            <deviceFriendlyName>101</deviceFriendlyName>
+            <deviceFriendlyName>108</deviceFriendlyName>
+            <deviceFriendlyName>108</deviceFriendlyName>
+            <deviceFriendlyName>101</deviceFriendlyName>
+            <deviceFriendlyName>0</deviceFriendlyName>
+            <deviceFriendlyName>0</deviceFriendlyName>
+            <deviceFriendlyName>0</deviceFriendlyName>
+            <deviceFriendlyName>0</deviceFriendlyName>
+            <deviceFriendlyName>0</deviceFriendlyName>
+          </deviceFriendlyName>
+        </dibDeviceInfo>
+        <dibSuppSvcFamilies>
+          <descriptionType>2</descriptionType>
+          <serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpCore">
+              <version>1</version>
+            </serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpDeviceManagement">
+              <version>1</version>
+            </serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpTunneling">
+              <version>1</version>
+            </serviceIds>
+          </serviceIds>
+        </dibSuppSvcFamilies>
+      </SearchResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Description Request</name>
+    <raw>06100203000e0801000000000000</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <DescriptionRequest className="org.apache.plc4x.java.knxnetip.readwrite.DescriptionRequest">
+        <hpaiControlEndpoint>
+          <hostProtocolCode>1</hostProtocolCode>
+          <ipAddress>
+            <addr>
+              <addr>0</addr>
+              <addr>0</addr>
+              <addr>0</addr>
+              <addr>0</addr>
+            </addr>
+          </ipAddress>
+          <ipPort>0</ipPort>
+        </hpaiControlEndpoint>
+      </DescriptionRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Description Response</name>
+    <raw>06100204004436010200ffff000000082d409852e000170c000ab327553647697261204b4e582f49502d5363686e6974747374656c6c6500000000000802020103010401</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <DescriptionResponse className="org.apache.plc4x.java.knxnetip.readwrite.DescriptionResponse">
+        <dibDeviceInfo>
+          <descriptionType>1</descriptionType>
+          <knxMedium>2</knxMedium>
+          <deviceStatus>
+            <programMode>false</programMode>
+          </deviceStatus>
+          <knxAddress>
+            <mainGroup>15</mainGroup>
+            <middleGroup>15</middleGroup>
+            <subGroup>255</subGroup>
+          </knxAddress>
+          <projectInstallationIdentifier>
+            <projectNumber>0</projectNumber>
+            <installationNumber>0</installationNumber>
+          </projectInstallationIdentifier>
+          <knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>0</knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>8</knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>45</knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>64</knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>152</knxNetIpDeviceSerialNumber>
+            <knxNetIpDeviceSerialNumber>82</knxNetIpDeviceSerialNumber>
+          </knxNetIpDeviceSerialNumber>
+          <knxNetIpDeviceMulticastAddress>
+            <addr>
+              <addr>224</addr>
+              <addr>0</addr>
+              <addr>23</addr>
+              <addr>12</addr>
+            </addr>
+          </knxNetIpDeviceMulticastAddress>
+          <knxNetIpDeviceMacAddress>
+            <addr>
+              <addr>0</addr>
+              <addr>10</addr>
+              <addr>179</addr>
+              <addr>39</addr>
+              <addr>85</addr>
+              <addr>54</addr>
+            </addr>
+          </knxNetIpDeviceMacAddress>
+          <deviceFriendlyName>
+            <deviceFriendlyName>71</deviceFriendlyName>
+            <deviceFriendlyName>105</deviceFriendlyName>
+            <deviceFriendlyName>114</deviceFriendlyName>
+            <deviceFriendlyName>97</deviceFriendlyName>
+            <deviceFriendlyName>32</deviceFriendlyName>
+            <deviceFriendlyName>75</deviceFriendlyName>
+            <deviceFriendlyName>78</deviceFriendlyName>
+            <deviceFriendlyName>88</deviceFriendlyName>
+            <deviceFriendlyName>47</deviceFriendlyName>
+            <deviceFriendlyName>73</deviceFriendlyName>
+            <deviceFriendlyName>80</deviceFriendlyName>
+            <deviceFriendlyName>45</deviceFriendlyName>
+            <deviceFriendlyName>83</deviceFriendlyName>
+            <deviceFriendlyName>99</deviceFriendlyName>
+            <deviceFriendlyName>104</deviceFriendlyName>
+            <deviceFriendlyName>110</deviceFriendlyName>
+            <deviceFriendlyName>105</deviceFriendlyName>
+            <deviceFriendlyName>116</deviceFriendlyName>
+            <deviceFriendlyName>116</deviceFriendlyName>
+            <deviceFriendlyName>115</deviceFriendlyName>
+            <deviceFriendlyName>116</deviceFriendlyName>
+            <deviceFriendlyName>101</deviceFriendlyName>
+            <deviceFriendlyName>108</deviceFriendlyName>
+            <deviceFriendlyName>108</deviceFriendlyName>
+            <deviceFriendlyName>101</deviceFriendlyName>
+            <deviceFriendlyName>0</deviceFriendlyName>
+            <deviceFriendlyName>0</deviceFriendlyName>
+            <deviceFriendlyName>0</deviceFriendlyName>
+            <deviceFriendlyName>0</deviceFriendlyName>
+            <deviceFriendlyName>0</deviceFriendlyName>
+          </deviceFriendlyName>
+        </dibDeviceInfo>
+        <dibSuppSvcFamilies>
+          <descriptionType>2</descriptionType>
+          <serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpCore">
+              <version>1</version>
+            </serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpDeviceManagement">
+              <version>1</version>
+            </serviceIds>
+            <serviceIds className="org.apache.plc4x.java.knxnetip.readwrite.KnxNetIpTunneling">
+              <version>1</version>
+            </serviceIds>
+          </serviceIds>
+        </dibSuppSvcFamilies>
+      </DescriptionResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Connect Request</name>
+    <raw>06100205001a0801c0a82a46f4310801c0a82a46f43204040200</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <ConnectionRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequest">
+        <hpaiDiscoveryEndpoint>
+          <hostProtocolCode>1</hostProtocolCode>
+          <ipAddress>
+            <addr>
+              <addr>192</addr>
+              <addr>168</addr>
+              <addr>42</addr>
+              <addr>70</addr>
+            </addr>
+          </ipAddress>
+          <ipPort>62513</ipPort>
+        </hpaiDiscoveryEndpoint>
+        <hpaiDataEndpoint>
+          <hostProtocolCode>1</hostProtocolCode>
+          <ipAddress>
+            <addr>
+              <addr>192</addr>
+              <addr>168</addr>
+              <addr>42</addr>
+              <addr>70</addr>
+            </addr>
+          </ipAddress>
+          <ipPort>62514</ipPort>
+        </hpaiDataEndpoint>
+        <connectionRequestInformation className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequestInformationTunnelConnection">
+          <knxLayer>2</knxLayer>
+        </connectionRequestInformation>
+      </ConnectionRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Connect Response</name>
+    <raw>06100206001466000801c0a82a0b0e5704041101</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <ConnectionResponse className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionResponse">
+        <communicationChannelId>102</communicationChannelId>
+        <status>0</status>
+        <hpaiDataEndpoint>
+          <hostProtocolCode>1</hostProtocolCode>
+          <ipAddress>
+            <addr>
+              <addr>192</addr>
+              <addr>168</addr>
+              <addr>42</addr>
+              <addr>11</addr>
+            </addr>
+          </ipAddress>
+          <ipPort>3671</ipPort>
+        </hpaiDataEndpoint>
+        <connectionResponseDataBlock className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionResponseDataBlockTunnelConnection">
+          <knxAddress>
+            <mainGroup>1</mainGroup>
+            <middleGroup>1</middleGroup>
+            <subGroup>1</subGroup>
+          </knxAddress>
+        </connectionResponseDataBlock>
+      </ConnectionResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Connection State Request</name>
+    <raw>06100207001066000801c0a82a46f431</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <ConnectionStateRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionStateRequest">
+        <communicationChannelId>102</communicationChannelId>
+        <hpaiControlEndpoint>
+          <hostProtocolCode>1</hostProtocolCode>
+          <ipAddress>
+            <addr>
+              <addr>192</addr>
+              <addr>168</addr>
+              <addr>42</addr>
+              <addr>70</addr>
+            </addr>
+          </ipAddress>
+          <ipPort>62513</ipPort>
+        </hpaiControlEndpoint>
+      </ConnectionStateRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Connection State Response</name>
+    <raw>0610020800086600</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <ConnectionStateResponse className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionStateResponse">
+        <communicationChannelId>102</communicationChannelId>
+        <status>0</status>
+      </ConnectionStateResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Device Configuration Request</name>
+    <raw>06100310001104670000fc000001531001</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <DeviceConfigurationRequest className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationRequest">
+        <deviceConfigurationRequestDataBlock>
+          <communicationChannelId>103</communicationChannelId>
+          <sequenceCounter>0</sequenceCounter>
+        </deviceConfigurationRequestDataBlock>
+        <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMIMPropReadReq">
+          <interfaceObjectType>0</interfaceObjectType>
+          <objectInstance>1</objectInstance>
+          <propertyId>83</propertyId>
+          <numberOfElements>1</numberOfElements>
+          <startIndex>1</startIndex>
+        </cemi>
+      </DeviceConfigurationRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Device Configuration Ack</name>
+    <raw>06100311000a04670000</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <DeviceConfigurationAck className="org.apache.plc4x.java.knxnetip.readwrite.DeviceConfigurationAck">
+        <deviceConfigurationAckDataBlock>
+          <communicationChannelId>103</communicationChannelId>
+          <sequenceCounter>0</sequenceCounter>
+          <status>0</status>
+        </deviceConfigurationAckDataBlock>
+      </DeviceConfigurationAck>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Disconnect Request</name>
+    <raw>06100209001067000801c0a82a46f431</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <DisconnectRequest className="org.apache.plc4x.java.knxnetip.readwrite.DisconnectRequest">
+        <communicationChannelId>103</communicationChannelId>
+        <hpaiControlEndpoint>
+          <hostProtocolCode>1</hostProtocolCode>
+          <ipAddress>
+            <addr>
+              <addr>192</addr>
+              <addr>168</addr>
+              <addr>42</addr>
+              <addr>70</addr>
+            </addr>
+          </ipAddress>
+          <ipPort>62513</ipPort>
+        </hpaiControlEndpoint>
+      </DisconnectRequest>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Disconnect Response</name>
+    <raw>0610020a00086600</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <DisconnectResponse className="org.apache.plc4x.java.knxnetip.readwrite.DisconnectResponse">
+        <communicationChannelId>102</communicationChannelId>
+        <status>0</status>
+      </DisconnectResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Tunneling Request</name>
+    <raw>06100420001c046b00002b0703010504024502bc360a1e0ce100810d</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <TunnelingRequest className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingRequest">
+        <tunnelingRequestDataBlock>
+          <communicationChannelId>107</communicationChannelId>
+          <sequenceCounter>0</sequenceCounter>
+        </tunnelingRequestDataBlock>
+        <cemi className="org.apache.plc4x.java.knxnetip.readwrite.CEMILBusmonInd">
+          <additionalInformationLength>7</additionalInformationLength>
+          <additionalInformation>
+            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationBusmonitorInfo">
+              <frameErrorFlag>false</frameErrorFlag>
+              <bitErrorFlag>false</bitErrorFlag>
+              <parityErrorFlag>false</parityErrorFlag>
+              <unknownFlag>false</unknownFlag>
+              <lostFlag>false</lostFlag>
+              <sequenceNumber>5</sequenceNumber>
+            </additionalInformation>
+            <additionalInformation className="org.apache.plc4x.java.knxnetip.readwrite.CEMIAdditionalInformationRelativeTimestamp">
+              <relativeTimestamp>
+                <timestamp>17666</timestamp>
+              </relativeTimestamp>
+            </additionalInformation>
+          </additionalInformation>
+          <rawFrame>
+            <rawFrame>188</rawFrame>
+            <rawFrame>54</rawFrame>
+            <rawFrame>10</rawFrame>
+            <rawFrame>30</rawFrame>
+            <rawFrame>12</rawFrame>
+            <rawFrame>225</rawFrame>
+            <rawFrame>0</rawFrame>
+            <rawFrame>129</rawFrame>
+            <rawFrame>13</rawFrame>
+          </rawFrame>
+        </cemi>
+      </TunnelingRequest>
+
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Tunneling Response</name>
+    <raw>06100421000a046b0000</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <TunnelingResponse className="org.apache.plc4x.java.knxnetip.readwrite.TunnelingResponse">
+        <tunnelingResponseDataBlock>
+          <communicationChannelId>107</communicationChannelId>
+          <sequenceCounter>0</sequenceCounter>
+          <status>0</status>
+        </tunnelingResponseDataBlock>
+      </TunnelingResponse>
+    </xml>
+  </testcase>
+
+  <testcase>
+    <name>Default</name>
+    <raw>0610020500180801c0a82a46c4090801c0a82a46c40a0203</raw>
+    <root-type>KNXNetIPMessage</root-type>
+    <xml>
+      <ConnectionRequest className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequest">
+        <hpaiDiscoveryEndpoint>
+          <hostProtocolCode>1</hostProtocolCode>
+          <ipAddress>
+            <addr>
+              <addr>192</addr>
+              <addr>168</addr>
+              <addr>42</addr>
+              <addr>70</addr>
+            </addr>
+          </ipAddress>
+          <ipPort>50185</ipPort>
+        </hpaiDiscoveryEndpoint>
+        <hpaiDataEndpoint>
+          <hostProtocolCode>1</hostProtocolCode>
+          <ipAddress>
+            <addr>
+              <addr>192</addr>
+              <addr>168</addr>
+              <addr>42</addr>
+              <addr>70</addr>
+            </addr>
+          </ipAddress>
+          <ipPort>50186</ipPort>
+        </hpaiDataEndpoint>
+        <connectionRequestInformation className="org.apache.plc4x.java.knxnetip.readwrite.ConnectionRequestInformationDeviceManagement"/>
+      </ConnectionRequest>
+    </xml>
+  </testcase>
+
+</test:testsuite>
\ No newline at end of file