diff --git a/src/smpclient/transport/udp.py b/src/smpclient/transport/udp.py index 9e4e568..af38d93 100644 --- a/src/smpclient/transport/udp.py +++ b/src/smpclient/transport/udp.py @@ -137,7 +137,8 @@ def max_unencoded_size(self) -> int: """Maximum UDP payload size (MSS) to avoid fragmentation. Subtracts IPv4/IPv6 and UDP header overhead from MTU per RFC 8085 section 3.2. - The IP version is auto-detected after connection. + The IP version is auto-detected after connection. Once the server's MCUmgr + parameters are known, the payload is also capped at its advertised buffer. """ overhead = IPV6_UDP_OVERHEAD if self._is_ipv6 else IPV4_UDP_OVERHEAD - return self._mtu - overhead + return min(self._mtu - overhead, self._smp_server_transport_buffer_size or self._mtu) diff --git a/tests/test_smp_udp_transport.py b/tests/test_smp_udp_transport.py index 6096b59..845fb70 100644 --- a/tests/test_smp_udp_transport.py +++ b/tests/test_smp_udp_transport.py @@ -132,6 +132,17 @@ def test_max_unencoded_size_custom_mtu() -> None: assert t.max_unencoded_size == 484 +@pytest.mark.parametrize( + "buf_size, expected", + [(384, 384), (1472, 1472), (2048, 1472)], +) +def test_max_unencoded_size_capped_by_server_buffer(buf_size: int, expected: int) -> None: + """Zephyr copies each datagram into one `buf_size` buffer, so neither bound may be exceeded.""" + t = SMPUDPTransport(mtu=1500) + t.initialize(buf_size) + assert t.max_unencoded_size == expected + + @pytest.mark.asyncio async def test_ipv4_detection_real_socket() -> None: """Test IPv4 auto-detection with real socket connection."""