diff --git a/clippy.toml b/clippy.toml
index f3c4fee..52df439 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -1 +1 @@
-future-size-threshold = 200
+future-size-threshold = 300
diff --git a/edge-nal-embassy/Cargo.toml b/edge-nal-embassy/Cargo.toml
index d3a4f37..63a3c83 100644
--- a/edge-nal-embassy/Cargo.toml
+++ b/edge-nal-embassy/Cargo.toml
@@ -11,13 +11,21 @@ categories = [
     "embedded",
     "no-std::no-alloc",
     "asynchronous",
-    "network-programming"
+    "network-programming",
 ]
 
 [dependencies]
 embedded-io-async = { workspace = true }
 edge-nal = { workspace = true }
 heapless = { workspace = true }
-# TODO: Do not require these features and conditionalize the code instead
-embassy-net = { version = "0.4", features = ["tcp", "udp", "dns", "proto-ipv6", "medium-ethernet", "proto-ipv4", "igmp"] }
+# Do not require these features and conditionalize the code instead
+embassy-net = { version = "0.5", features = [
+    "tcp",
+    "udp",
+    "dns",
+    "proto-ipv6",
+    "medium-ethernet",
+    "proto-ipv4",
+    "multicast",
+] }
 embassy-futures = { workspace = true }
diff --git a/edge-nal-embassy/README.md b/edge-nal-embassy/README.md
index 3df5501..bde536b 100644
--- a/edge-nal-embassy/README.md
+++ b/edge-nal-embassy/README.md
@@ -14,9 +14,8 @@ All traits except `Readable` which - while implemented - panics if called.
 
 ### UDP
 
-* All traits except `UdpConnect`. 
+* All traits except `UdpConnect`.
 * `MulticastV6` - while implemented - panics if `join_v6` / `leave_v6` are called.
-* `Readable` - while implemented - panics if called.
 
 ### Raw sockets
 
diff --git a/edge-nal-embassy/src/dns.rs b/edge-nal-embassy/src/dns.rs
index 1d16cbb..865ff6b 100644
--- a/edge-nal-embassy/src/dns.rs
+++ b/edge-nal-embassy/src/dns.rs
@@ -4,37 +4,25 @@ use edge_nal::AddrType;
 
 use embassy_net::{
     dns::{DnsQueryType, Error},
-    driver::Driver,
     Stack,
 };
 use embedded_io_async::ErrorKind;
 
-use crate::to_net_addr;
-
 /// A struct that implements the `Dns` trait from `edge-nal`
-pub struct Dns<'a, D>
-where
-    D: Driver + 'static,
-{
-    stack: &'a Stack<D>,
+pub struct Dns<'a> {
+    stack: Stack<'a>,
 }
 
-impl<'a, D> Dns<'a, D>
-where
-    D: Driver + 'static,
-{
+impl<'a> Dns<'a> {
     /// Create a new `Dns` instance for the provided Embassy networking stack
     ///
     /// NOTE: If using DHCP, make sure it has reconfigured the stack to ensure the DNS servers are updated
-    pub fn new(stack: &'a Stack<D>) -> Self {
+    pub fn new(stack: Stack<'a>) -> Self {
         Self { stack }
     }
 }
 
-impl<'a, D> edge_nal::Dns for Dns<'a, D>
-where
-    D: Driver + 'static,
-{
+impl edge_nal::Dns for Dns<'_> {
     type Error = DnsError;
 
     async fn get_host_by_name(
@@ -48,7 +36,7 @@ where
         };
         let addrs = self.stack.dns_query(host, qtype).await?;
         if let Some(first) = addrs.first() {
-            Ok(to_net_addr(*first))
+            Ok((*first).into())
         } else {
             Err(Error::Failed.into())
         }
diff --git a/edge-nal-embassy/src/lib.rs b/edge-nal-embassy/src/lib.rs
index 6761a3f..5fdc7c8 100644
--- a/edge-nal-embassy/src/lib.rs
+++ b/edge-nal-embassy/src/lib.rs
@@ -4,10 +4,10 @@
 
 use core::cell::{Cell, UnsafeCell};
 use core::mem::MaybeUninit;
-use core::net::{IpAddr, SocketAddr};
+use core::net::SocketAddr;
 use core::ptr::NonNull;
 
-use embassy_net::{IpAddress, IpEndpoint, IpListenEndpoint};
+use embassy_net::IpEndpoint;
 
 pub use dns::*;
 pub use tcp::*;
@@ -25,6 +25,7 @@ pub(crate) struct Pool<T, const N: usize> {
 impl<T, const N: usize> Pool<T, N> {
     #[allow(clippy::declare_interior_mutable_const)]
     const VALUE: Cell<bool> = Cell::new(false);
+    #[allow(clippy::declare_interior_mutable_const)]
     const UNINIT: UnsafeCell<MaybeUninit<T>> = UnsafeCell::new(MaybeUninit::uninit());
 
     const fn new() -> Self {
@@ -59,7 +60,7 @@ impl<T, const N: usize> Pool<T, N> {
 }
 
 pub(crate) fn to_net_socket(socket: IpEndpoint) -> SocketAddr {
-    SocketAddr::new(to_net_addr(socket.addr), socket.port)
+    SocketAddr::new(socket.addr.into(), socket.port)
 }
 
 // pub(crate) fn to_net_socket2(socket: IpListenEndpoint) -> SocketAddr {
@@ -71,43 +72,3 @@ pub(crate) fn to_net_socket(socket: IpEndpoint) -> SocketAddr {
 //         socket.port,
 //     )
 // }
-
-pub(crate) fn to_emb_socket(socket: SocketAddr) -> IpEndpoint {
-    IpEndpoint {
-        addr: to_emb_addr(socket.ip()),
-        port: socket.port(),
-    }
-}
-
-pub(crate) fn to_emb_bind_socket(socket: SocketAddr) -> IpListenEndpoint {
-    IpListenEndpoint {
-        addr: (!socket.ip().is_unspecified()).then(|| to_emb_addr(socket.ip())),
-        port: socket.port(),
-    }
-}
-
-pub(crate) fn to_net_addr(addr: IpAddress) -> IpAddr {
-    match addr {
-        //#[cfg(feature = "proto-ipv4")]
-        IpAddress::Ipv4(addr) => addr.0.into(),
-        // #[cfg(not(feature = "proto-ipv4"))]
-        // IpAddr::V4(_) => panic!("ipv4 support not enabled"),
-        //#[cfg(feature = "proto-ipv6")]
-        IpAddress::Ipv6(addr) => addr.0.into(),
-        // #[cfg(not(feature = "proto-ipv6"))]
-        // IpAddr::V6(_) => panic!("ipv6 support not enabled"),
-    }
-}
-
-pub(crate) fn to_emb_addr(addr: IpAddr) -> IpAddress {
-    match addr {
-        //#[cfg(feature = "proto-ipv4")]
-        IpAddr::V4(addr) => IpAddress::Ipv4(embassy_net::Ipv4Address::from_bytes(&addr.octets())),
-        // #[cfg(not(feature = "proto-ipv4"))]
-        // IpAddr::V4(_) => panic!("ipv4 support not enabled"),
-        //#[cfg(feature = "proto-ipv6")]
-        IpAddr::V6(addr) => IpAddress::Ipv6(embassy_net::Ipv6Address::from_bytes(&addr.octets())),
-        // #[cfg(not(feature = "proto-ipv6"))]
-        // IpAddr::V6(_) => panic!("ipv6 support not enabled"),
-    }
-}
diff --git a/edge-nal-embassy/src/tcp.rs b/edge-nal-embassy/src/tcp.rs
index 8e86906..2575a68 100644
--- a/edge-nal-embassy/src/tcp.rs
+++ b/edge-nal-embassy/src/tcp.rs
@@ -6,37 +6,33 @@ use edge_nal::{Close, Readable, TcpBind, TcpConnect, TcpShutdown, TcpSplit};
 
 use embassy_futures::join::join;
 
-use embassy_net::driver::Driver;
 use embassy_net::tcp::{AcceptError, ConnectError, Error, TcpReader, TcpWriter};
 use embassy_net::Stack;
 
 use embedded_io_async::{ErrorKind, ErrorType, Read, Write};
 
-use crate::{to_emb_bind_socket, to_emb_socket, to_net_socket, Pool};
+use crate::{to_net_socket, Pool};
 
 /// A struct that implements the `TcpConnect` and `TcpBind` factory traits from `edge-nal`
 /// Capable of managing up to N concurrent connections with TX and RX buffers according to TX_SZ and RX_SZ.
-pub struct Tcp<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024>
-{
-    stack: &'d Stack<D>,
+pub struct Tcp<'d, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> {
+    stack: Stack<'d>,
     buffers: &'d TcpBuffers<N, TX_SZ, RX_SZ>,
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize>
-    Tcp<'d, D, N, TX_SZ, RX_SZ>
-{
+impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> Tcp<'d, N, TX_SZ, RX_SZ> {
     /// Create a new `Tcp` instance for the provided Embassy networking stack, using the provided TCP buffers
     ///
     /// Ensure that the number of buffers `N` fits within StackResources<N> of
     /// [embassy_net::Stack], while taking into account the sockets used for DHCP, DNS, etc. else
     /// [smoltcp::iface::SocketSet] will panic with `adding a socket to a full SocketSet`.
-    pub fn new(stack: &'d Stack<D>, buffers: &'d TcpBuffers<N, TX_SZ, RX_SZ>) -> Self {
+    pub fn new(stack: Stack<'d>, buffers: &'d TcpBuffers<N, TX_SZ, RX_SZ>) -> Self {
         Self { stack, buffers }
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpConnect
-    for Tcp<'d, D, N, TX_SZ, RX_SZ>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpConnect
+    for Tcp<'_, N, TX_SZ, RX_SZ>
 {
     type Error = TcpError;
 
@@ -48,19 +44,17 @@ impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpC
     async fn connect(&self, remote: SocketAddr) -> Result<Self::Socket<'_>, Self::Error> {
         let mut socket = TcpSocket::new(self.stack, self.buffers)?;
 
-        socket.socket.connect(to_emb_socket(remote)).await?;
+        socket.socket.connect(remote).await?;
 
         Ok(socket)
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpBind
-    for Tcp<'d, D, N, TX_SZ, RX_SZ>
-{
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpBind for Tcp<'_, N, TX_SZ, RX_SZ> {
     type Error = TcpError;
 
     type Accept<'a>
-        = TcpAccept<'a, D, N, TX_SZ, RX_SZ>
+        = TcpAccept<'a, N, TX_SZ, RX_SZ>
     where
         Self: 'a;
 
@@ -70,19 +64,13 @@ impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpB
 }
 
 /// Represents an acceptor for incoming TCP client connections. Implements the `TcpAccept` factory trait from `edge-nal`
-pub struct TcpAccept<
-    'd,
-    D: Driver,
-    const N: usize,
-    const TX_SZ: usize = 1024,
-    const RX_SZ: usize = 1024,
-> {
-    stack: &'d Tcp<'d, D, N, TX_SZ, RX_SZ>,
+pub struct TcpAccept<'d, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> {
+    stack: &'d Tcp<'d, N, TX_SZ, RX_SZ>,
     local: SocketAddr,
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> edge_nal::TcpAccept
-    for TcpAccept<'d, D, N, TX_SZ, RX_SZ>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> edge_nal::TcpAccept
+    for TcpAccept<'_, N, TX_SZ, RX_SZ>
 {
     type Error = TcpError;
 
@@ -94,7 +82,7 @@ impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> edge
     async fn accept(&self) -> Result<(SocketAddr, Self::Socket<'_>), Self::Error> {
         let mut socket = TcpSocket::new(self.stack.stack, self.stack.buffers)?;
 
-        socket.socket.accept(to_emb_bind_socket(self.local)).await?;
+        socket.socket.accept(self.local).await?;
 
         let local_endpoint = socket.socket.local_endpoint().unwrap();
 
@@ -111,8 +99,8 @@ pub struct TcpSocket<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize>
 }
 
 impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpSocket<'d, N, TX_SZ, RX_SZ> {
-    fn new<D: Driver>(
-        stack: &'d Stack<D>,
+    fn new(
+        stack: Stack<'d>,
         stack_buffers: &'d TcpBuffers<N, TX_SZ, RX_SZ>,
     ) -> Result<Self, TcpError> {
         let mut socket_buffers = stack_buffers.pool.alloc().ok_or(TcpError::NoBuffers)?;
@@ -171,8 +159,8 @@ impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpSocket<'d, N
     }
 }
 
-impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> Drop
-    for TcpSocket<'d, N, TX_SZ, RX_SZ>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> Drop
+    for TcpSocket<'_, N, TX_SZ, RX_SZ>
 {
     fn drop(&mut self) {
         unsafe {
@@ -182,22 +170,22 @@ impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> Drop
     }
 }
 
-impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> ErrorType
-    for TcpSocket<'d, N, TX_SZ, RX_SZ>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> ErrorType
+    for TcpSocket<'_, N, TX_SZ, RX_SZ>
 {
     type Error = TcpError;
 }
 
-impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> Read
-    for TcpSocket<'d, N, TX_SZ, RX_SZ>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> Read
+    for TcpSocket<'_, N, TX_SZ, RX_SZ>
 {
     async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
         Ok(self.socket.read(buf).await?)
     }
 }
 
-impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> Write
-    for TcpSocket<'d, N, TX_SZ, RX_SZ>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> Write
+    for TcpSocket<'_, N, TX_SZ, RX_SZ>
 {
     async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
         Ok(self.socket.write(buf).await?)
@@ -210,16 +198,17 @@ impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> Write
     }
 }
 
-impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> Readable
-    for TcpSocket<'d, N, TX_SZ, RX_SZ>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> Readable
+    for TcpSocket<'_, N, TX_SZ, RX_SZ>
 {
     async fn readable(&mut self) -> Result<(), Self::Error> {
-        panic!("Not implemented yet")
+        self.socket.wait_read_ready().await;
+        Ok(())
     }
 }
 
-impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpShutdown
-    for TcpSocket<'d, N, TX_SZ, RX_SZ>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpShutdown
+    for TcpSocket<'_, N, TX_SZ, RX_SZ>
 {
     async fn close(&mut self, what: Close) -> Result<(), Self::Error> {
         TcpSocket::close(self, what).await
@@ -234,19 +223,20 @@ impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpShutdown
 /// Implements the `Read` trait from `embedded-io-async`
 pub struct TcpSocketRead<'a>(TcpReader<'a>);
 
-impl<'a> ErrorType for TcpSocketRead<'a> {
+impl ErrorType for TcpSocketRead<'_> {
     type Error = TcpError;
 }
 
-impl<'a> Read for TcpSocketRead<'a> {
+impl Read for TcpSocketRead<'_> {
     async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
         self.0.read(buf).await.map_err(TcpError::from)
     }
 }
 
-impl<'a> Readable for TcpSocketRead<'a> {
+impl Readable for TcpSocketRead<'_> {
     async fn readable(&mut self) -> Result<(), Self::Error> {
-        panic!("Not implemented yet")
+        self.0.wait_read_ready().await;
+        Ok(())
     }
 }
 
@@ -254,11 +244,11 @@ impl<'a> Readable for TcpSocketRead<'a> {
 /// Implements the `Write` trait from `embedded-io-async`
 pub struct TcpSocketWrite<'a>(TcpWriter<'a>);
 
-impl<'a> ErrorType for TcpSocketWrite<'a> {
+impl ErrorType for TcpSocketWrite<'_> {
     type Error = TcpError;
 }
 
-impl<'a> Write for TcpSocketWrite<'a> {
+impl Write for TcpSocketWrite<'_> {
     async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
         self.0.write(buf).await.map_err(TcpError::from)
     }
@@ -268,8 +258,8 @@ impl<'a> Write for TcpSocketWrite<'a> {
     }
 }
 
-impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpSplit
-    for TcpSocket<'d, N, TX_SZ, RX_SZ>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpSplit
+    for TcpSocket<'_, N, TX_SZ, RX_SZ>
 {
     type Read<'a>
         = TcpSocketRead<'a>
@@ -332,6 +322,14 @@ pub struct TcpBuffers<const N: usize, const TX_SZ: usize, const RX_SZ: usize> {
     pool: Pool<([u8; TX_SZ], [u8; RX_SZ]), N>,
 }
 
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> Default
+    for TcpBuffers<N, TX_SZ, RX_SZ>
+{
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
 impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpBuffers<N, TX_SZ, RX_SZ> {
     /// Create a new `TcpBuffers` instance
     pub const fn new() -> Self {
diff --git a/edge-nal-embassy/src/udp.rs b/edge-nal-embassy/src/udp.rs
index 9f4f89f..5c2d10f 100644
--- a/edge-nal-embassy/src/udp.rs
+++ b/edge-nal-embassy/src/udp.rs
@@ -3,55 +3,53 @@ use core::ptr::NonNull;
 
 use edge_nal::{MulticastV4, MulticastV6, Readable, UdpBind, UdpReceive, UdpSend, UdpSplit};
 
-use embassy_net::driver::Driver;
 use embassy_net::udp::{BindError, PacketMetadata, RecvError, SendError};
 use embassy_net::{MulticastError, Stack};
 
 use embedded_io_async::{ErrorKind, ErrorType};
 
-use crate::{to_emb_addr, to_emb_bind_socket, to_emb_socket, to_net_socket, Pool};
+use crate::{to_net_socket, Pool};
 
 /// A struct that implements the `UdpBind` factory trait from `edge-nal`
 /// Capable of managing up to N concurrent connections with TX and RX buffers according to TX_SZ and RX_SZ, and packet metadata according to `M`.
 pub struct Udp<
     'd,
-    D: Driver,
     const N: usize,
     const TX_SZ: usize = 1500,
     const RX_SZ: usize = 1500,
     const M: usize = 2,
 > {
-    stack: &'d Stack<D>,
+    stack: Stack<'d>,
     buffers: &'d UdpBuffers<N, TX_SZ, RX_SZ, M>,
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
-    Udp<'d, D, N, TX_SZ, RX_SZ, M>
+impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
+    Udp<'d, N, TX_SZ, RX_SZ, M>
 {
     /// Create a new `Udp` instance for the provided Embassy networking stack using the provided UDP buffers.
     ///
     /// Ensure that the number of buffers `N` fits within StackResources<N> of
     /// [embassy_net::Stack], while taking into account the sockets used for DHCP, DNS, etc. else
     /// [smoltcp::iface::SocketSet] will panic with `adding a socket to a full SocketSet`.
-    pub fn new(stack: &'d Stack<D>, buffers: &'d UdpBuffers<N, TX_SZ, RX_SZ, M>) -> Self {
+    pub fn new(stack: Stack<'d>, buffers: &'d UdpBuffers<N, TX_SZ, RX_SZ, M>) -> Self {
         Self { stack, buffers }
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> UdpBind
-    for Udp<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> UdpBind
+    for Udp<'_, N, TX_SZ, RX_SZ, M>
 {
     type Error = UdpError;
 
     type Socket<'a>
-        = UdpSocket<'a, D, N, TX_SZ, RX_SZ, M>
+        = UdpSocket<'a, N, TX_SZ, RX_SZ, M>
     where
         Self: 'a;
 
     async fn bind(&self, local: SocketAddr) -> Result<Self::Socket<'_>, Self::Error> {
         let mut socket = UdpSocket::new(self.stack, self.buffers)?;
 
-        socket.socket.bind(to_emb_bind_socket(local))?;
+        socket.socket.bind(local)?;
 
         Ok(socket)
     }
@@ -59,26 +57,19 @@ impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, cons
 
 /// A UDP socket
 /// Implements the `UdpReceive` `UdpSend` and `UdpSplit` traits from `edge-nal`
-pub struct UdpSocket<
-    'd,
-    D: Driver,
-    const N: usize,
-    const TX_SZ: usize,
-    const RX_SZ: usize,
-    const M: usize,
-> {
-    stack: &'d embassy_net::Stack<D>,
+pub struct UdpSocket<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> {
+    stack: embassy_net::Stack<'d>,
     socket: embassy_net::udp::UdpSocket<'d>,
     stack_buffers: &'d UdpBuffers<N, TX_SZ, RX_SZ, M>,
     socket_buffers: NonNull<([u8; TX_SZ], [u8; RX_SZ])>,
     socket_meta_buffers: NonNull<([PacketMetadata; M], [PacketMetadata; M])>,
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
-    UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
+    UdpSocket<'d, N, TX_SZ, RX_SZ, M>
 {
     fn new(
-        stack: &'d Stack<D>,
+        stack: Stack<'d>,
         stack_buffers: &'d UdpBuffers<N, TX_SZ, RX_SZ, M>,
     ) -> Result<Self, UdpError> {
         let mut socket_buffers = stack_buffers.pool.alloc().ok_or(UdpError::NoBuffers)?;
@@ -102,8 +93,8 @@ impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, cons
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> Drop
-    for UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> Drop
+    for UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     fn drop(&mut self) {
         unsafe {
@@ -114,68 +105,69 @@ impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, cons
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
-    ErrorType for UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> ErrorType
+    for UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     type Error = UdpError;
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
-    UdpReceive for UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> UdpReceive
+    for UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     async fn receive(&mut self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Self::Error> {
         let (len, remote_endpoint) = self.socket.recv_from(buffer).await?;
 
-        Ok((len, to_net_socket(remote_endpoint)))
+        Ok((len, to_net_socket(remote_endpoint.endpoint)))
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> UdpSend
-    for UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> UdpSend
+    for UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     async fn send(&mut self, remote: SocketAddr, data: &[u8]) -> Result<(), Self::Error> {
-        self.socket.send_to(data, to_emb_socket(remote)).await?;
+        self.socket.send_to(data, remote).await?;
 
         Ok(())
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
-    ErrorType for &UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> ErrorType
+    for &UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     type Error = UdpError;
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
-    UdpReceive for &UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> UdpReceive
+    for &UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     async fn receive(&mut self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Self::Error> {
         let (len, remote_endpoint) = self.socket.recv_from(buffer).await?;
 
-        Ok((len, to_net_socket(remote_endpoint)))
+        Ok((len, to_net_socket(remote_endpoint.endpoint)))
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> UdpSend
-    for &UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> UdpSend
+    for &UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     async fn send(&mut self, remote: SocketAddr, data: &[u8]) -> Result<(), Self::Error> {
-        self.socket.send_to(data, to_emb_socket(remote)).await?;
+        self.socket.send_to(data, remote).await?;
 
         Ok(())
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> Readable
-    for &UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> Readable
+    for &UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     async fn readable(&mut self) -> Result<(), Self::Error> {
-        panic!("Not implemented yet")
+        self.socket.wait_recv_ready().await;
+        Ok(())
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> UdpSplit
-    for UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> UdpSplit
+    for UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     type Receive<'a>
         = &'a Self
@@ -192,8 +184,8 @@ impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, cons
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
-    MulticastV4 for UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> MulticastV4
+    for UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     async fn join_v4(
         &mut self,
@@ -201,8 +193,7 @@ impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, cons
         _interface: Ipv4Addr,
     ) -> Result<(), Self::Error> {
         self.stack
-            .join_multicast_group(to_emb_addr(IpAddr::V4(multicast_addr)))
-            .await?;
+            .join_multicast_group(IpAddr::V4(multicast_addr))?;
 
         Ok(())
     }
@@ -213,38 +204,44 @@ impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, cons
         _interface: Ipv4Addr,
     ) -> Result<(), Self::Error> {
         self.stack
-            .leave_multicast_group(to_emb_addr(IpAddr::V4(multicast_addr)))
-            .await?;
+            .leave_multicast_group(IpAddr::V4(multicast_addr))?;
 
         Ok(())
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
-    MulticastV6 for UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> MulticastV6
+    for UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     async fn join_v6(
         &mut self,
-        _multicast_addr: Ipv6Addr,
+        multicast_addr: Ipv6Addr,
         _interface: u32,
     ) -> Result<(), Self::Error> {
-        panic!("Joining an Ipv6 multicast group is not supported yet")
+        self.stack
+            .join_multicast_group(IpAddr::V6(multicast_addr))?;
+
+        Ok(())
     }
 
     async fn leave_v6(
         &mut self,
-        _multicast_addr: Ipv6Addr,
+        multicast_addr: Ipv6Addr,
         _interface: u32,
     ) -> Result<(), Self::Error> {
-        panic!("Leaving an Ipv6 multicast group is not supported yet")
+        self.stack
+            .leave_multicast_group(IpAddr::V6(multicast_addr))?;
+
+        Ok(())
     }
 }
 
-impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> Readable
-    for UdpSocket<'d, D, N, TX_SZ, RX_SZ, M>
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> Readable
+    for UdpSocket<'_, N, TX_SZ, RX_SZ, M>
 {
     async fn readable(&mut self) -> Result<(), Self::Error> {
-        panic!("Not implemented yet")
+        self.socket.wait_recv_ready().await;
+        Ok(())
     }
 }
 
@@ -307,6 +304,14 @@ pub struct UdpBuffers<const N: usize, const TX_SZ: usize, const RX_SZ: usize, co
     >,
 }
 
+impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize> Default
+    for UdpBuffers<N, TX_SZ, RX_SZ, M>
+{
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
 impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize, const M: usize>
     UdpBuffers<N, TX_SZ, RX_SZ, M>
 {