diff --git a/src/Groundstation/Common/Ports/EthernetBase.cpp b/src/Groundstation/Common/Ports/EthernetBase.cpp
index 52b2e982ab9f8b42fab1a529408c447377785fb6..e66be196a14ad83c826790d3cb63c6112335ee83 100644
--- a/src/Groundstation/Common/Ports/EthernetBase.cpp
+++ b/src/Groundstation/Common/Ports/EthernetBase.cpp
@@ -1,5 +1,5 @@
-/* Copyright (c) 2023 Skyward Experimental Rocketry
- * Author: Davide Mor
+/* Copyright (c) 2023-2024 Skyward Experimental Rocketry
+ * Authors: Davide Mor, Nicolò Caruso
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -65,7 +65,7 @@ Boardcore::Wiz5500::PhyState EthernetBase::getState()
     return wiz5500->getPhyState();
 }
 
-bool EthernetBase::start(std::unique_ptr<Boardcore::Wiz5500> wiz5500)
+bool EthernetBase::start(std::shared_ptr<Boardcore::Wiz5500> wiz5500)
 {
     this->wiz5500 = std::move(wiz5500);
 
@@ -103,16 +103,10 @@ bool EthernetBase::start(std::unique_ptr<Boardcore::Wiz5500> wiz5500)
         return false;
     }
 
-    if (sniffOtherGs)
+    if (!this->wiz5500->openUdp(1, SEND_PORT, {255, 255, 255, 255}, RECV_PORT,
+                                500))
     {
-        TRACE("[info] starting second UDP socket (inverse direction)\n");
-        if (!this->wiz5500->openUdp(1, SEND_PORT, {255, 255, 255, 255},
-                                    RECV_PORT, 500))
-
-        {
-            TRACE("[error] starting second UDP socket\n");
-            return false;
-        }
+        return false;
     }
 
     auto mav_handler = [this](EthernetMavDriver* channel,
@@ -122,7 +116,17 @@ bool EthernetBase::start(std::unique_ptr<Boardcore::Wiz5500> wiz5500)
 
     if (!mav_driver->start())
         return false;
+    TRACE("[info] mavlink driver started correctly\n");
 
+    // Create and start a second mavlink driver to sniff the ethernet port
+    if (sniffOtherGs)
+    {
+        getModule<EthernetSniffer>()->init(1, RECV_PORT, SEND_PORT);
+        if (!getModule<EthernetSniffer>()->start(wiz5500))
+            return false;
+    }
+
+    TRACE("[info] Ethernet sniffing started correctly\n");
     return true;
 }
 
@@ -134,26 +138,13 @@ void EthernetBase::handleMsg(const mavlink_message_t& msg)
 
 ssize_t EthernetBase::receive(uint8_t* pkt, size_t max_len)
 {
-    ssize_t size = 0;
     WizIp dst_ip;
     uint16_t dst_port;
-    if (!sniffOtherGs)
-        size = wiz5500->recvfrom(0, pkt, max_len, dst_ip, dst_port);
-    else
-        // In case of sniffing, there is a maximum waiting time for messages
-        // from the groundstation software to switch between one and other port
-        size = wiz5500->recvfrom(0, pkt, max_len, dst_ip, dst_port,
-                                 RECEIVE_PORT_TIMEOUT_MS);
-    if (size <= 0 && sniffOtherGs)
-    {
-        size = wiz5500->recvfrom(1, pkt, max_len, dst_ip, dst_port,
-                                 RECEIVE_PORT_TIMEOUT_MS);
-    }
-    return size;
+    return wiz5500->recvfrom(0, pkt, max_len, dst_ip, dst_port);
 }
 
 bool EthernetBase::send(uint8_t* pkt, size_t len)
 {
-    return wiz5500->send(0, pkt, len, 100);
+    return wiz5500->send(0, pkt, len, 1000);
     // return true;
 }
diff --git a/src/Groundstation/Common/Ports/EthernetBase.h b/src/Groundstation/Common/Ports/EthernetBase.h
index 82adc3c1a059cb1f629c8f531f7bad927f766dba..57e6622e50e7be804694ae030ecf4afc25df5104 100644
--- a/src/Groundstation/Common/Ports/EthernetBase.h
+++ b/src/Groundstation/Common/Ports/EthernetBase.h
@@ -1,5 +1,5 @@
-/* Copyright (c) 2023 Skyward Experimental Rocketry
- * Author: Davide Mor
+/* Copyright (c) 2023-2024 Skyward Experimental Rocketry
+ * Authors: Davide Mor, Nicolò Caruso
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -24,6 +24,7 @@
 
 #include <ActiveObject.h>
 #include <Groundstation/Common/HubBase.h>
+#include <Groundstation/Common/Ports/EthernetSniffer.h>
 #include <common/MavlinkLyra.h>
 #include <drivers/WIZ5500/WIZ5500.h>
 #include <radio/MavlinkDriver/MavlinkDriver.h>
@@ -43,8 +44,9 @@ Boardcore::WizMac genNewRandomMac();
 using EthernetMavDriver =
     Boardcore::MavlinkDriver<1024, 10, MAVLINK_MAX_DIALECT_PAYLOAD_SIZE>;
 
-class EthernetBase : public Boardcore::Transceiver,
-                     public Boardcore::InjectableWithDeps<HubBase>
+class EthernetBase
+    : public Boardcore::Transceiver,
+      public Boardcore::InjectableWithDeps<HubBase, EthernetSniffer>
 {
 public:
     EthernetBase() {};
@@ -58,8 +60,8 @@ public:
     Boardcore::Wiz5500::PhyState getState();
 
 protected:
-    bool start(std::unique_ptr<Boardcore::Wiz5500> wiz5500);
-    std::unique_ptr<Boardcore::Wiz5500> wiz5500;
+    bool start(std::shared_ptr<Boardcore::Wiz5500> wiz5500);
+    std::shared_ptr<Boardcore::Wiz5500> wiz5500;
 
 private:
     /**
@@ -76,6 +78,7 @@ private:
     bool randomIp     = true;
     uint8_t ipOffset  = 0;
     bool sniffOtherGs = false;
+    bool firstPort    = true;
 };
 
 }  // namespace Groundstation
diff --git a/src/Groundstation/Common/Ports/EthernetSniffer.cpp b/src/Groundstation/Common/Ports/EthernetSniffer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8b6be2b7f09a511e06630f8e675e04b4ae95da92
--- /dev/null
+++ b/src/Groundstation/Common/Ports/EthernetSniffer.cpp
@@ -0,0 +1,101 @@
+/* Copyright (c) 2025 Skyward Experimental Rocketry
+ * Author: Nicolò Caruso
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <Groundstation/Common/Config/EthernetConfig.h>
+#include <Groundstation/Common/HubBase.h>
+
+#include <random>
+
+#include "EthernetBase.h"
+
+using namespace Groundstation;
+using namespace Boardcore;
+using namespace miosix;
+
+void EthernetSniffer::handleINTn()
+{
+    if (wiz5500)
+        wiz5500->handleINTn();
+}
+
+bool EthernetSniffer::send(uint8_t* pkt, size_t len)
+{
+    // Send is not needed in sniffing, therefore not implemented
+    return false;
+};
+
+Boardcore::Wiz5500::PhyState EthernetSniffer::getState()
+{
+    return wiz5500->getPhyState();
+}
+
+void EthernetSniffer::init(uint16_t portNumber, uint16_t srcPort,
+                           uint16_t dstPort)
+{
+    portNr  = portNumber;
+    srcPort = srcPort;
+    dstPort = dstPort;
+}
+
+bool EthernetSniffer::start(std::shared_ptr<Boardcore::Wiz5500> wiz5500)
+{
+    TRACE("Movin\n");
+    this->wiz5500 = std::move(wiz5500);
+
+    TRACE("Opening\n");
+    // We open the port for sniffing using the port we specified
+    // if (!this->wiz5500->openUdp(portNr, srcPort, {255, 255, 255, 255},
+    // dstPort,
+    //                             500))
+    // {
+    //     return false;
+    // }
+
+    TRACE("Mavlinker\n");
+
+    auto mav_handler = [this](EthernetMavDriver* channel,
+                              const mavlink_message_t& msg) { handleMsg(msg); };
+
+    mav_driver = std::make_unique<EthernetMavDriver>(this, mav_handler, 1, 10);
+
+    TRACE("Starting\n");
+
+    if (!mav_driver->start())
+        return false;
+
+    TRACE("Start ok\n");
+
+    return true;
+}
+
+void EthernetSniffer::handleMsg(const mavlink_message_t& msg)
+{
+    // Dispatch the message through the hub.
+    getModule<HubBase>()->dispatchOutgoingMsg(msg);
+}
+
+ssize_t EthernetSniffer::receive(uint8_t* pkt, size_t max_len)
+{
+    WizIp dst_ip;
+    uint16_t dst_port;
+    return wiz5500->recvfrom(portNr, pkt, max_len, dst_ip, dst_port);
+}
diff --git a/src/Groundstation/Common/Ports/EthernetSniffer.h b/src/Groundstation/Common/Ports/EthernetSniffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f4ea7a74340f2bd367d761b11c254f6117ca1e0
--- /dev/null
+++ b/src/Groundstation/Common/Ports/EthernetSniffer.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2025 Skyward Experimental Rocketry
+ * Author: Nicolò Caruso
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <ActiveObject.h>
+#include <Groundstation/Common/HubBase.h>
+#include <common/MavlinkLyra.h>
+#include <drivers/WIZ5500/WIZ5500.h>
+#include <radio/MavlinkDriver/MavlinkDriver.h>
+#include <utils/DependencyManager/DependencyManager.h>
+
+#include <memory>
+
+namespace Groundstation
+{
+
+using EthernetMavDriver =
+    Boardcore::MavlinkDriver<1024, 10, MAVLINK_MAX_DIALECT_PAYLOAD_SIZE>;
+
+class EthernetSniffer : public Boardcore::Transceiver,
+                        public Boardcore::InjectableWithDeps<HubBase>
+{
+public:
+    void handleINTn();
+
+    Boardcore::Wiz5500::PhyState getState();
+
+    bool start(std::shared_ptr<Boardcore::Wiz5500> wiz5500);
+
+    void init(uint16_t portNumber, uint16_t srcPort, uint16_t dstPort);
+
+private:
+    std::shared_ptr<Boardcore::Wiz5500> wiz5500;
+
+    /**
+     * @brief Called internally when a message is received.
+     */
+    void handleMsg(const mavlink_message_t& msg);
+
+    ssize_t receive(uint8_t* pkt, size_t max_len) override;
+
+    bool send(uint8_t* pkt, size_t len) override;
+
+    bool started = false;
+    std::unique_ptr<EthernetMavDriver> mav_driver;
+    uint16_t portNr;
+    uint16_t srcPort;
+    uint16_t dstPort;
+};
+
+}  // namespace Groundstation
diff --git a/src/Groundstation/LyraGS/Ports/Ethernet.cpp b/src/Groundstation/LyraGS/Ports/Ethernet.cpp
index 6b3e3270fc12fa4186473c77f74e6cf6f1c58d41..6013c835a97d4865c89e5e161228ab1a9ab59198 100644
--- a/src/Groundstation/LyraGS/Ports/Ethernet.cpp
+++ b/src/Groundstation/LyraGS/Ports/Ethernet.cpp
@@ -45,7 +45,7 @@ namespace LyraGS
 
 bool EthernetGS::start()
 {
-    std::unique_ptr<Wiz5500> wiz5500 = std::make_unique<Wiz5500>(
+    std::shared_ptr<Wiz5500> wiz5500 = std::make_shared<Wiz5500>(
         getModule<Buses>()->ethernet_bus, miosix::ethernet::cs::getPin(),
         miosix::ethernet::intr::getPin(), SPI::ClockDivider::DIV_64);
 
@@ -55,7 +55,7 @@ bool EthernetGS::start()
     if (!present)
         return false;
 
-    if (!EthernetBase::start(std::move(wiz5500)))
+    if (!EthernetBase::start(wiz5500))
         return false;
 
     ethernetGSGlobal = this;
diff --git a/src/Groundstation/LyraGS/lyra-gs-entry.cpp b/src/Groundstation/LyraGS/lyra-gs-entry.cpp
index 26ab6211c476afe08739d64e5051cca61e677f1f..29a0fdef2900ea8db8ced03dfc31c57e1f253603 100644
--- a/src/Groundstation/LyraGS/lyra-gs-entry.cpp
+++ b/src/Groundstation/LyraGS/lyra-gs-entry.cpp
@@ -93,6 +93,8 @@ void errorLoop()
     }
 }
 
+static bool constexpr ethernetSniffing = true;
+
 /**
  * @brief Lyra GS entrypoint.
  * This entrypoint performs the following operations:
@@ -141,7 +143,8 @@ int main()
         new LyraGS::RadioMain(dipRead.mainHasBackup, dipRead.mainTXenable);
     LyraGS::BoardStatus* board_status = new LyraGS::BoardStatus(dipRead.isARP);
     LyraGS::EthernetGS* ethernet =
-        new LyraGS::EthernetGS(false, dipRead.ipConfig, true);
+        new LyraGS::EthernetGS(false, dipRead.ipConfig, ethernetSniffing);
+    EthernetSniffer* ethernetSniffer    = new EthernetSniffer();
     LyraGS::RadioPayload* radio_payload = new LyraGS::RadioPayload(
         dipRead.payloadHasBackup, dipRead.payloadTXenable);
 
@@ -160,6 +163,7 @@ int main()
     ok &= manager.insert(serial);
     ok &= manager.insert<LyraGS::RadioMain>(radio_main);
     ok &= manager.insert<LyraGS::EthernetGS>(ethernet);
+    ok &= manager.insert<EthernetSniffer>(ethernetSniffer);
     ok &= manager.insert<LyraGS::RadioPayload>(radio_payload);
     ok &= manager.insert(board_status);