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 2021/07/04 15:15:39 UTC

[plc4x] branch feature/profinet-chris updated: - Managed to implement a first working version of Profinet auto-discovery working.

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

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


The following commit(s) were added to refs/heads/feature/profinet-chris by this push:
     new e0bd3cb  - Managed to implement a first working version of Profinet auto-discovery working.
e0bd3cb is described below

commit e0bd3cbcc2f78f9faab4b9f1174ebf850b31fbc3
Author: cdutz <ch...@c-ware.de>
AuthorDate: Sun Jul 4 17:15:27 2021 +0200

    - Managed to implement a first working version of Profinet auto-discovery working.
---
 .../org/apache/plc4x/java/PlcDriverManager.java    |   1 -
 .../org/apache/plc4x/java/api/Experimental.java    |   1 -
 .../plc4x/java/api/PlcConnectionExtension.java     |   1 -
 .../api/exceptions/PlcFieldRangeException.java     |   1 -
 .../PlcIncompatibleDatatypeException.java          |   1 -
 .../exceptions/PlcProtocolTimeoutException.java    |  34 +--
 .../java/api/exceptions/PlcTimeoutException.java   |   1 -
 .../PlcUnsupportedProtocolException.java           |   1 -
 .../java/api/model/PlcConsumerRegistration.java    |   1 -
 ...rRegistration.java => PlcDiscoveryHandler.java} |  19 +-
 .../plc4x/java/api/model/PlcSubscriptionField.java |  34 +--
 .../org/apache/plc4x/java/api/value/PlcValue.java  |   1 -
 .../plc4x/java/api/value/PlcValueHandler.java      |   1 -
 plc4j/drivers/profinet/pom.xml                     |  21 +-
 .../apache/plc4x/java/profinet/ProfinetDriver.java |  10 +-
 .../ProfinetDiscoveryContext.java}                 |  11 +-
 .../profinet/discovery/ProfinetPlcDiscoverer.java  | 228 +++++++++++++++++++++
 .../ProfinetDiscoveryLogic.java}                   |  16 +-
 .../plc4x/java/profinet/utils/StaticHelper.java    |   4 +
 .../resources/protocols/profinet/profinet.mspec    |  28 +--
 20 files changed, 323 insertions(+), 92 deletions(-)

diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java b/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java
index e3a3fbe..13c3979 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java
@@ -18,7 +18,6 @@
  */
 package org.apache.plc4x.java;
 
-import org.apache.plc4x.java.api.Experimental;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.authentication.PlcAuthentication;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/Experimental.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/Experimental.java
index 8d2d8d3..d43824c 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/Experimental.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/Experimental.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.plc4x.java.api;
 
 /**
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcConnectionExtension.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcConnectionExtension.java
index 208a155..1e8ac84 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcConnectionExtension.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcConnectionExtension.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.plc4x.java.api;
 
 import org.apache.commons.lang3.NotImplementedException;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcFieldRangeException.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcFieldRangeException.java
index f3908f4..c156f5f 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcFieldRangeException.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcFieldRangeException.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.plc4x.java.api.exceptions;
 
 public class PlcFieldRangeException extends PlcRuntimeException {
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcIncompatibleDatatypeException.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcIncompatibleDatatypeException.java
index 64ee10d..dfb2f86 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcIncompatibleDatatypeException.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcIncompatibleDatatypeException.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.plc4x.java.api.exceptions;
 
 public class PlcIncompatibleDatatypeException extends PlcRuntimeException {
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcProtocolTimeoutException.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcProtocolTimeoutException.java
index 193e97f..ec7f2e7 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcProtocolTimeoutException.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcProtocolTimeoutException.java
@@ -1,21 +1,21 @@
 /*
-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.
-*/
+ * 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.api.exceptions;
 
 public class PlcProtocolTimeoutException extends PlcProtocolException {
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcTimeoutException.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcTimeoutException.java
index ed83dd5..373c8e0 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcTimeoutException.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcTimeoutException.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.plc4x.java.api.exceptions;
 
 import java.util.concurrent.TimeUnit;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcUnsupportedProtocolException.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcUnsupportedProtocolException.java
index 2ec7db9..3cb6e3f 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcUnsupportedProtocolException.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/exceptions/PlcUnsupportedProtocolException.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.plc4x.java.api.exceptions;
 
 public class PlcUnsupportedProtocolException extends PlcConnectionException {
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
index f885564..7ce72ba 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.plc4x.java.api.model;
 
 import java.util.List;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcDiscoveryHandler.java
similarity index 73%
copy from plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
copy to plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcDiscoveryHandler.java
index f885564..5cb9724 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcConsumerRegistration.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcDiscoveryHandler.java
@@ -16,21 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.plc4x.java.api.model;
 
-import java.util.List;
-
-/**
- * Represents the registration of one consumer for a given subscription handle.
- * Also provides the means to unsubscribe.
- */
-public interface PlcConsumerRegistration {
-
-    Integer getConsumerId();
+import org.apache.plc4x.java.api.messages.PlcDiscoveryItem;
 
-    List<PlcSubscriptionHandle> getSubscriptionHandles();
+public interface PlcDiscoveryHandler {
 
-    void unregister();
+    /**
+     * Callback that gets called as soon as we found a new PlcDiscoveryItem
+     * @param item a PlcDiscoveryItem identifying a newly found resource
+     */
+    void handle(PlcDiscoveryItem item);
 
 }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java
index e05c286..3d0dcd7 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionField.java
@@ -1,21 +1,21 @@
 /*
-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.
-*/
+ * 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.api.model;
 
 import org.apache.plc4x.java.api.types.PlcSubscriptionType;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java
index 47df920..52fbc4e 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValue.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.plc4x.java.api.value;
 
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueHandler.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueHandler.java
index 67d6055..3ade947 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueHandler.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/value/PlcValueHandler.java
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.plc4x.java.api.value;
 
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
diff --git a/plc4j/drivers/profinet/pom.xml b/plc4j/drivers/profinet/pom.xml
index 60fecd6..1188ee9 100644
--- a/plc4j/drivers/profinet/pom.xml
+++ b/plc4j/drivers/profinet/pom.xml
@@ -132,6 +132,12 @@
       <artifactId>plc4j-utils-pcap-shared</artifactId>
       <version>0.9.0-SNAPSHOT</version>
     </dependency>
+    <dependency>
+      <groupId>org.pcap4j</groupId>
+      <artifactId>pcap4j-core</artifactId>
+      <!-- Override the "provided" scope -->
+      <scope>compile</scope>
+    </dependency>
 
     <dependency>
       <groupId>io.netty</groupId>
@@ -153,7 +159,20 @@
     <dependency>
       <groupId>ch.qos.logback</groupId>
       <artifactId>logback-classic</artifactId>
-      <scope>test</scope>
+      <!-- TODO: Just for now -->
+      <scope>compile</scope>
+    </dependency>
+    <!-- TODO: Just for now -->
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-core</artifactId>
+      <scope>runtime</scope>
+    </dependency>
+    <!-- TODO: Just for now -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <scope>compile</scope>
     </dependency>
 
     <dependency>
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
index 055b147..0a261f7 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
@@ -23,6 +23,7 @@ import org.apache.plc4x.java.api.messages.PlcDiscoveryRequest;
 import org.apache.plc4x.java.api.messages.PlcDiscoveryResponse;
 import org.apache.plc4x.java.api.metadata.PlcDriverMetadata;
 import org.apache.plc4x.java.profinet.config.ProfinetConfiguration;
+import org.apache.plc4x.java.profinet.discovery.ProfinetPlcDiscoverer;
 import org.apache.plc4x.java.profinet.field.ProfinetField;
 import org.apache.plc4x.java.profinet.field.ProfinetFieldHandler;
 import org.apache.plc4x.java.profinet.protocol.ProfinetProtocolLogic;
@@ -43,7 +44,7 @@ import org.apache.plc4x.java.spi.optimizer.SingleFieldOptimizer;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.ToIntFunction;
 
-public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> implements PlcDiscoverer {
+public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> {
 
     @Override
     public String getProtocolCode() {
@@ -67,7 +68,7 @@ public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> implement
 
     @Override
     public PlcDiscoveryRequest.Builder discoveryRequestBuilder() {
-        return new DefaultPlcDiscoveryRequest.Builder(this);
+        return new DefaultPlcDiscoveryRequest.Builder(new ProfinetPlcDiscoverer());
     }
 
     @Override
@@ -149,9 +150,4 @@ public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> implement
         return ProfinetField.of(query);
     }
 
-    @Override
-    public CompletableFuture<PlcDiscoveryResponse> discover(PlcDiscoveryRequest discoveryRequest) {
-        return null;
-    }
-
 }
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDiscoveryContext.java
similarity index 77%
copy from plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
copy to plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDiscoveryContext.java
index 984d8ff..c3e7d43 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/context/ProfinetDiscoveryContext.java
@@ -16,15 +16,10 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.profinet.utils;
+package org.apache.plc4x.java.profinet.context;
 
-public class StaticHelper {
+import org.apache.plc4x.java.spi.context.DriverContext;
 
-    public static int stringLength(String str) {
-        if (str == null) {
-            return 0;
-        }
-        return str.length();
-    }
+public class ProfinetDiscoveryContext implements DriverContext {
 
 }
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
new file mode 100644
index 0000000..18865c0
--- /dev/null
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/discovery/ProfinetPlcDiscoverer.java
@@ -0,0 +1,228 @@
+/*
+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.profinet.discovery;
+
+import org.apache.plc4x.java.api.messages.PlcDiscoveryRequest;
+import org.apache.plc4x.java.api.messages.PlcDiscoveryResponse;
+import org.apache.plc4x.java.profinet.readwrite.*;
+import org.apache.plc4x.java.profinet.readwrite.io.EthernetFrameIO;
+import org.apache.plc4x.java.profinet.readwrite.types.VirtualLanPriority;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.ReadBufferByteBased;
+import org.apache.plc4x.java.spi.generation.WriteBufferByteBased;
+import org.apache.plc4x.java.spi.messages.PlcDiscoverer;
+import org.pcap4j.core.*;
+import org.pcap4j.packet.Dot1qVlanTagPacket;
+import org.pcap4j.packet.EthernetPacket;
+import org.pcap4j.packet.IllegalRawDataException;
+import org.pcap4j.packet.Packet;
+import org.pcap4j.packet.namednumber.EtherType;
+import org.pcap4j.util.LinkLayerAddress;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class ProfinetPlcDiscoverer implements PlcDiscoverer {
+
+    private static final EtherType PN_EtherType = EtherType.getInstance((short) 0x8892);
+
+    private static final String DEVICE_TYPE_NAME = "DEVICE_PROPERTIES_OPTION-1";
+    private static final String DEVICE_NAME_OF_STATION = "DEVICE_PROPERTIES_OPTION-2";
+    private static final String DEVICE_ID = "DEVICE_PROPERTIES_OPTION-3";
+    private static final String DEVICE_ROLE = "DEVICE_PROPERTIES_OPTION-4";
+    private static final String DEVICE_OPTIONS = "DEVICE_PROPERTIES_OPTION-5";
+    private static final String DEVICE_INSTANCE = "DEVICE_PROPERTIES_OPTION-7";
+    private static final String IP_OPTION_IP = "IP_OPTION-2";
+
+    public ProfinetPlcDiscoverer() {
+    }
+
+    @Override
+    public CompletableFuture<PlcDiscoveryResponse> discover(PlcDiscoveryRequest discoveryRequest) {
+        Map<String, DCP_Identify_ResPDU> pnDevices = new HashMap<>();
+        try {
+            for (PcapNetworkInterface dev : Pcaps.findAllDevs()) {
+                if(!dev.isLoopBack() && dev.isRunning()) {
+                    for (LinkLayerAddress linkLayerAddress : dev.getLinkLayerAddresses()) {
+                        org.pcap4j.util.MacAddress macAddress = (org.pcap4j.util.MacAddress) linkLayerAddress;
+                        PcapHandle handle = dev.openLive(65536, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 10);
+                        PcapHandle sendHandle = dev.openLive(65536, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 10);
+                        ExecutorService pool = Executors.newSingleThreadExecutor();
+
+                        // Only react on PROFINET DCP packets targeted at our current MAC address.
+                        // TODO: Find out how to filter based on the ether frame type ...
+                        handle.setFilter(
+                            "ether dst " + Pcaps.toBpfString(macAddress),
+                            BpfProgram.BpfCompileMode.OPTIMIZE);
+
+                        PacketListener listener =
+                            packet -> {
+                                if(packet instanceof EthernetPacket) {
+                                    EthernetPacket ethernetPacket = (EthernetPacket) packet;
+                                    boolean isPnPacket = false;
+                                    if(ethernetPacket.getPayload() instanceof Dot1qVlanTagPacket) {
+                                        Dot1qVlanTagPacket vlanPacket = (Dot1qVlanTagPacket) ethernetPacket.getPayload();
+                                        if(PN_EtherType.equals(vlanPacket.getHeader().getType())) {
+                                            isPnPacket = true;
+                                        }
+                                    } else if(PN_EtherType.equals(ethernetPacket.getHeader().getType())) {
+                                        isPnPacket = true;
+                                    }
+
+                                    // It's a PROFINET packet.
+                                    if(isPnPacket) {
+                                        ReadBuffer reader = new ReadBufferByteBased(ethernetPacket.getRawData());
+                                        try {
+                                            EthernetFrame ethernetFrame = EthernetFrameIO.staticParse(reader);
+                                            String sourceMacAddress = toMacAddressString(ethernetFrame.getSource());
+                                            DCP_PDU pdu;
+                                            if(ethernetFrame.getPayload() instanceof VirtualLanEthernetFramePayload) {
+                                                VirtualLanEthernetFramePayload vlefpl = (VirtualLanEthernetFramePayload) ethernetFrame.getPayload();
+                                                pdu = ((ProfinetEthernetFramePayload) vlefpl.getPayload()).getPdu();
+                                            } else {
+                                                pdu = ((ProfinetEthernetFramePayload) ethernetFrame.getPayload()).getPdu();
+                                            }
+                                            if(pdu instanceof DCP_Identify_ResPDU) {
+                                                DCP_Identify_ResPDU identify_resPDU = (DCP_Identify_ResPDU) pdu;
+                                                if(!pnDevices.containsKey(sourceMacAddress)) {
+                                                    pnDevices.put(sourceMacAddress, identify_resPDU);
+                                                }
+                                            }
+                                        } catch (ParseException e) {
+                                            e.printStackTrace();
+                                        }
+                                    }
+                                }
+                            };
+                        Task t = new Task(handle, listener);
+                        pool.execute(t);
+
+                        // Construct and send the search request.
+                        EthernetFrame identificationRequest = new EthernetFrame(
+                            // Pre-Defined PROFINET discovery MAC address
+                            new MacAddress(new short[]{0x01, 0x0E, 0xCF, 0x00, 0x00, 0x00}),
+                            toPlc4xMacAddress(macAddress),
+                            new VirtualLanEthernetFramePayload(VirtualLanPriority.BEST_EFFORT, false, 0,
+                                new ProfinetEthernetFramePayload(
+                                    new DCP_Identify_ReqPDU(
+                                        new ServiceType(false, false),
+                                        1,
+                                        256,
+                                        new DCP_Block[]{
+                                            new DCP_BlockALLSelector()
+                                        }))));
+                        WriteBufferByteBased buffer = new WriteBufferByteBased(34);
+                        EthernetFrameIO.staticSerialize(buffer, identificationRequest);
+                        Packet packet = EthernetPacket.newPacket(buffer.getData(), 0, 34);
+                        sendHandle.sendPacket(packet);
+                    }
+                }
+            }
+        } catch (PcapNativeException | ParseException e) {
+            e.printStackTrace();
+        } catch (NotOpenException e) {
+            e.printStackTrace();
+        } catch (IllegalRawDataException e) {
+            e.printStackTrace();
+        }
+        try {
+            Thread.sleep(5000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        System.out.println(String.format("Found %d PROFINET devices:", pnDevices.size()));
+        for (DCP_Identify_ResPDU pnDevice : pnDevices.values()) {
+            outputPnDevice(pnDevice);
+        }
+
+        return null;
+    }
+
+    private static MacAddress toPlc4xMacAddress(org.pcap4j.util.MacAddress pcap4jMacAddress) {
+        byte[] address = pcap4jMacAddress.getAddress();
+        return new MacAddress(new short[]{ (short) address[0], (short) address[1], (short) address[2], (short) address[3], (short) address[4], (short) address[5]});
+    }
+
+    private static String toMacAddressString(MacAddress macAddress) {
+        return String.format("%x2:%x2:%x2:%x2:%x2:%x2", macAddress.getAddress()[0], macAddress.getAddress()[1],
+            macAddress.getAddress()[2], macAddress.getAddress()[3], macAddress.getAddress()[4], macAddress.getAddress()[5]);
+    }
+
+    private static void outputPnDevice(DCP_Identify_ResPDU pnDevice) {
+        Map<String, DCP_Block> blocks = new HashMap<>();
+        for (DCP_Block block : pnDevice.getBlocks()) {
+            String blockName = block.getOption().name() + "-" + block.getSuboption().toString();
+            blocks.put(blockName, block);
+        }
+
+        String deviceTypeName = "unknown";
+        if(blocks.containsKey(DEVICE_TYPE_NAME)) {
+            DCP_BlockDevicePropertiesDeviceVendor block = (DCP_BlockDevicePropertiesDeviceVendor) blocks.get(DEVICE_TYPE_NAME);
+            deviceTypeName = new String(block.getDeviceVendorValue());
+        }
+        String deviceName = "unknown";
+        if(blocks.containsKey(DEVICE_NAME_OF_STATION)) {
+            DCP_BlockDevicePropertiesNameOfStation block = (DCP_BlockDevicePropertiesNameOfStation) blocks.get(DEVICE_NAME_OF_STATION);
+            deviceName = new String(block.getNameOfStation());
+        }
+        String ipAddress = "unknown";
+        if(blocks.containsKey(IP_OPTION_IP)) {
+            DCP_BlockIpIpParameter block = (DCP_BlockIpIpParameter) blocks.get(IP_OPTION_IP);
+            ipAddress = String.format("%d.%d.%d.%d", block.getIpAddress()[0], block.getIpAddress()[1], block.getIpAddress()[2], block.getIpAddress()[3]);
+        }
+        System.out.println(String.format("Found '%s' with name '%s' on IP: %s%n\t%s", deviceTypeName, deviceName, ipAddress, pnDevice));
+    }
+
+    private static class Task implements Runnable {
+
+        private PcapHandle handle;
+        private PacketListener listener;
+
+        public Task(PcapHandle handle, PacketListener listener) {
+            this.handle = handle;
+            this.listener = listener;
+        }
+
+        @Override
+        public void run() {
+            try {
+                handle.loop(10, listener);
+            } catch (PcapNativeException e) {
+                e.printStackTrace();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            } catch (NotOpenException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        ProfinetPlcDiscoverer discoverer = new ProfinetPlcDiscoverer();
+        discoverer.discover(null);
+
+        Thread.sleep(10000);
+    }
+
+}
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetDiscoveryLogic.java
similarity index 66%
copy from plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
copy to plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetDiscoveryLogic.java
index 984d8ff..fe886c2 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/protocol/ProfinetDiscoveryLogic.java
@@ -16,15 +16,17 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.java.profinet.utils;
+package org.apache.plc4x.java.profinet.protocol;
 
-public class StaticHelper {
+import org.apache.plc4x.java.profinet.readwrite.EthernetFrame;
+import org.apache.plc4x.java.spi.ConversationContext;
+import org.apache.plc4x.java.spi.Plc4xProtocolBase;
+
+public class ProfinetDiscoveryLogic extends Plc4xProtocolBase<EthernetFrame> {
+
+    @Override
+    public void close(ConversationContext<EthernetFrame> context) {
 
-    public static int stringLength(String str) {
-        if (str == null) {
-            return 0;
-        }
-        return str.length();
     }
 
 }
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
index 984d8ff..2a3351c 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/utils/StaticHelper.java
@@ -27,4 +27,8 @@ public class StaticHelper {
         return str.length();
     }
 
+    public static int arrayLength(byte[] arr) {
+        return arr.length;
+    }
+
 }
diff --git a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
index 90ad1af..d9d2138 100644
--- a/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
+++ b/protocols/profinet/src/main/resources/protocols/profinet/profinet.mspec
@@ -49,7 +49,7 @@
     // 4.3.1.3.5 (Page 95ff)
     [simple        uint 16          'responseDelayFactorOrPadding']
     // 4.3.1.3.4 (Page 95)
-    [implicit      uint 16          'dcpDataLength' 'lengthInBytes - 10']
+    [implicit      uint 16          'dcpDataLength' 'lengthInBytes - 12']
     [typeSwitch 'frameId','serviceId','serviceType.response'
         ////////////////////////////////////////////////////////////////////////////
         // Multicast (Well theoretically)
@@ -108,7 +108,7 @@
 [discriminatedType 'DCP_Block'
     [discriminator BlockOptions 'option'                                                ]
     [discriminator uint 8       'suboption'                                             ]
-    [implicit      uint 16      'blockLength' 'lengthInBytes'                           ]
+    [implicit      uint 16      'blockLength' 'lengthInBytes - 4'                       ]
     [typeSwitch 'option','suboption'
 
         ////////////////////////////////////////////////////////////////////////////
@@ -139,17 +139,17 @@
         // DEVICE_PROPERTIES_OPTION
         ////////////////////////////////////////////////////////////////////////////
 
-        ['DEVICE_PROPERTIES_OPTION','1' DCP_BlockDevicePropertiesDeviceVendor
+        ['DEVICE_PROPERTIES_OPTION','1' DCP_BlockDevicePropertiesDeviceVendor [uint 16 'blockLength']
             [reserved uint 16     '0x0000'                                              ]
             // TODO: Figure out how to do this correctly.
-            [simple   string '-1' 'deviceVendorValue'                                   ]
-            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.stringLength", deviceVendorValue) % 2'     ]
+            [array    byte        'deviceVendorValue' count 'blockLength-2'             ]
+            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.arrayLength", deviceVendorValue) % 2']
         ]
-        ['DEVICE_PROPERTIES_OPTION','2' DCP_BlockDevicePropertiesNameOfStation
+        ['DEVICE_PROPERTIES_OPTION','2' DCP_BlockDevicePropertiesNameOfStation [uint 16 'blockLength']
             [reserved uint 16     '0x0000'                                              ]
             // TODO: Figure out how to do this correctly.
-            [simple   string '-1' 'nameOfStation'                                       ]
-            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.stringLength", nameOfStation) % 2'         ]
+            [array    byte        'nameOfStation' count 'blockLength-2'                 ]
+            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.arrayLength", nameOfStation) % 2']
         ]
         ['DEVICE_PROPERTIES_OPTION','3' DCP_BlockDevicePropertiesDeviceId
             [reserved uint 16 '0x0000'                                                  ]
@@ -162,16 +162,17 @@
             [simple   bit     'pnioMultidevive'                                         ]
             [simple   bit     'pnioController'                                          ]
             [simple   bit     'pnioDevice'                                              ]
+            [reserved uint 8  '0x00'                                                    ]
         ]
         // Contains a list of option combinations the device supports.
         ['DEVICE_PROPERTIES_OPTION','5' DCP_BlockDevicePropertiesDeviceOptions [uint 16 'blockLength']
             [reserved uint 16               '0x0000'                                    ]
             [array    SupportedDeviceOption 'supportedOptions' length 'blockLength - 2' ]
         ]
-        ['DEVICE_PROPERTIES_OPTION','6' DCP_BlockDevicePropertiesAliasName
+        ['DEVICE_PROPERTIES_OPTION','6' DCP_BlockDevicePropertiesAliasName [uint 16 'blockLength']
             [reserved uint 16     '0x0000'                                              ]
-            [simple   string '-1' 'aliasNameValue'                                      ]
-            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.stringLength", aliasNameValue) % 2'       ]
+            [array    byte        'aliasNameValue' count 'blockLength-2'                ]
+            [padding  uint 8      'pad' '0x00' 'STATIC_CALL("org.apache.plc4x.java.profinet.utils.StaticHelper.arrayLength", aliasNameValue) % 2']
         ]
         ['DEVICE_PROPERTIES_OPTION','7' DCP_BlockDevicePropertiesDeviceInstance
             [reserved uint 16 '0x0000'                                                  ]
@@ -328,9 +329,10 @@
     ['0xFF' ALL_SELECTOR_OPTION]
 ]
 
+// https://de.wikipedia.org/wiki/IEEE_802.1p
 [enum uint 3 'VirtualLanPriority'   [string '2' 'acronym']
-    ['0x0' BACKGROUND               ['BK'                ]]
-    ['0x1' BEST_EFFORT              ['BE'                ]]
+    ['0x0' BEST_EFFORT              ['BE'                ]]
+    ['0x1' BACKGROUND               ['BK'                ]]
     ['0x2' EXCELLENT_EFFORT         ['EE'                ]]
     ['0x3' CRITICAL_APPLICATIONS    ['CA'                ]]
     ['0x4' VIDEO                    ['VI'                ]]