public PacketListener createListener() {
        return packet -> {
            // EthernetPacket is the highest level of abstraction we can be expecting.
            // Everything inside this we will have to decode ourselves.
            if (packet instanceof EthernetPacket) {
                EthernetPacket ethernetPacket = (EthernetPacket) packet;
                boolean isPnPacket = false;
                // I have observed sometimes the ethernet packets being wrapped inside a VLAN
                // Packet, in this case we simply unpack the content.
                if (ethernetPacket.getPayload() instanceof Dot1qVlanTagPacket) {
                    Dot1qVlanTagPacket vlanPacket = (Dot1qVlanTagPacket) ethernetPacket.getPayload();
                    if (PN_EtherType.equals(vlanPacket.getHeader().getType()) || LLDP_EtherType.equals(vlanPacket.getHeader().getType())) {
                        isPnPacket = true;
                    }
                } else if (PN_EtherType.equals(ethernetPacket.getHeader().getType()) || LLDP_EtherType.equals(ethernetPacket.getHeader().getType())) {
                    isPnPacket = true;
                } else if (ethernetPacket.getHeader().getType() == EtherType.IPV4 && ethernetPacket.getPayload().getPayload() instanceof UdpPacket) {
                    UdpPacket payload = (UdpPacket) ethernetPacket.getPayload().getPayload();
                    // Check if it's a PROFINET packet
                    if (payload.getHeader().getDstPort().value() == -30572 || payload.getHeader().getDstPort().value() == -15536 || payload.getHeader().getDstPort().value() == -15535) {
                        isPnPacket = true;
                    }
                }

                if (isPnPacket) {
                    ReadBuffer reader = new ReadBufferByteBased(ethernetPacket.getRawData());
                    try {
                        Ethernet_Frame ethernetFrame = Ethernet_Frame.staticParse(reader);
                        Ethernet_FramePayload payload = ethernetFrame.getPayload();

                        // Virtual lan packets simply contain normal payloads, so we simply unpack them
                        if (payload instanceof Ethernet_FramePayload_VirtualLan) {
                            payload = ((Ethernet_FramePayload_VirtualLan) payload).getPayload();
                            // TODO: Possibly we could have multiple levels of VLans ...
                        }

                        // Pass the PN frame to the listeners.
                        for (BiConsumer<Ethernet_FramePayload, EthernetPacket> packetListener : packetListeners) {
                            packetListener.accept(payload, ethernetPacket);
                        }

                        /*if (payload instanceof Ethernet_FramePayload_PnDcp) {
                            PnDcp_Pdu pdu = ((Ethernet_FramePayload_PnDcp) payload).getPdu();
                            if (pdu.getFrameId() == PnDcp_FrameId.DCP_Identify_ResPDU) {
                                if (discoverer != null) {
                                    discoverer.processPnDcp(pdu, ethernetPacket);
                                }
                            } else if (pdu.getFrameId() == PnDcp_FrameId.DCP_GetSet_PDU) {
                                for (Map.Entry<String, ProfinetDevice> device : devices.entrySet()) {
                                    if (Arrays.equals(device.getValue().getDeviceContext().getMacAddress().getAddress(), ethernetFrame.getSource().getAddress())) {
                                        PcDcp_GetSet_Pdu getSetPdu = (PcDcp_GetSet_Pdu) pdu;
                                        device.getValue().handleSetIpAddressResponse(getSetPdu);
                                    }
                                }
                            } else if (pdu.getFrameId() == PnDcp_FrameId.Alarm_Low) {
                                    for (Map.Entry<String, ProfinetDevice> device : devices.entrySet()) {
                                        if (Arrays.equals(device.getValue().getDeviceContext().getMacAddress().getAddress(), ethernetFrame.getSource().getAddress())) {
                                            PnDcp_Pdu_AlarmLow alarmPdu = (PnDcp_Pdu_AlarmLow) pdu;
                                            device.getValue().handleAlarmResponse(alarmPdu);
                                        }
                                    }
                                }
                                else if (pdu.getFrameId() == PnDcp_FrameId.RT_CLASS_1) {
                                    for (Map.Entry<String, ProfinetDevice> device : devices.entrySet()) {
                                        if (device.getValue().getDeviceContext().getMacAddress() == null) {
                                            logger.info("Hurz");
                                        } else if (Arrays.equals(device.getValue().getDeviceContext().getMacAddress().getAddress(), ethernetFrame.getSource().getAddress())) {
                                            PnDcp_Pdu_RealTimeCyclic cyclicPdu = (PnDcp_Pdu_RealTimeCyclic) pdu;
                                            device.getValue().handleRealTimeResponse(cyclicPdu);
                                        }
                                    }
                                }
                        } else if (payload instanceof Ethernet_FramePayload_LLDP) {
                            Lldp_Pdu pdu = ((Ethernet_FramePayload_LLDP) payload).getPdu();
                            if (discoverer != null) {
                                discoverer.processLldp(pdu);
                            }
                        } else if (payload instanceof Ethernet_FramePayload_IPv4) {
                            Ethernet_FramePayload_IPv4 payloadIPv4 = (Ethernet_FramePayload_IPv4) payload;
                            if (payloadIPv4.getPayload().getPacketType() == DceRpc_PacketType.PING) {
                                DceRpc_Packet pingRequest = payloadIPv4.getPayload();
                                // Intercept ping packets that originated from the PN device itself.
                                // TODO: Find out how to react to PING messages.
                                // According to https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm the correct response for us to such a ping message would be a "working" response
                                Ethernet_Frame pingResponse = new Ethernet_Frame(ethernetFrame.getSource(), ethernetFrame.getDestination(),
                                    new Ethernet_FramePayload_IPv4(payloadIPv4.getIdentification(), false, false,
                                        payloadIPv4.getTimeToLive(), payloadIPv4.getDestinationAddress(),
                                        payloadIPv4.getSourceAddress(), payloadIPv4.getDestinationPort(),
                                        payloadIPv4.getSourcePort(), new DceRpc_Packet(DceRpc_PacketType.WORKING,
                                        false, false, false,
                                        IntegerEncoding.BIG_ENDIAN, CharacterEncoding.ASCII, FloatingPointEncoding.IEEE,
                                        pingRequest.getObjectUuid(), pingRequest.getInterfaceUuid(), pingRequest.getActivityUuid(),
                                        0L, 0L, DceRpc_Operation.CONNECT, (short) 0, new PnIoCm_Packet_Working())
                                        ));
                                this.send(pingResponse);

                                logger.info("Received PING packet: {}", packet);
                            } else {
                                for (Map.Entry<String, ProfinetDevice> device : devices.entrySet()) {
                                    if (Arrays.equals(device.getValue().getDeviceContext().getMacAddress().getAddress(), ethernetFrame.getSource().getAddress())) {
                                        device.getValue().handleResponse(payloadIPv4);
                                    }
                                }
                            }
                        }*/
                    } catch (ParseException e) {
                        logger.error("Got error decoding packet", e);
                    }
                }
            }
        };
    }
This code is borrowed and stripped down from the Profinet driver
plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/discovery/ProfinetChannel.java