[udp] Limit a split packet to the copy buffer

The copy buffer is sized by code generation to max_packet_size, but
set_max_packet_size() can raise the limit afterwards, and copying a split
packet would then overflow it. The link now takes the buffer as a span
and refuses a split packet larger than it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
clydebarrow
2026-10-19 14:40:33 +11:00
co-authored by Claude Opus 5.5
parent ef6bb95608
commit e633f54997
3 changed files with 22 additions and 5 deletions
@@ -35,8 +35,13 @@ bool UdpPacketInterface::send_to_interface(const PacketBuffer &data, const Packe
auto span = data.as_span();
return this->parent_->send_packet(span.data(), span.size());
}
data.copy_to(this->tx_buffer_, size);
return this->parent_->send_packet(this->tx_buffer_, size);
if (size > this->tx_buffer_.size()) {
ESP_LOGW(TAG, "%s: Packet of %zu bytes is larger than the %zu byte buffer", this->name_, size,
this->tx_buffer_.size());
return false;
}
data.copy_to(this->tx_buffer_.data(), size);
return this->parent_->send_packet(this->tx_buffer_.data(), size);
}
} // namespace esphome::udp
@@ -19,8 +19,10 @@ namespace esphome::udp {
*/
class UdpPacketInterface : public packet_interface::PacketInterface {
public:
/// @param tx_buffer Holds max_packet_size bytes, for packets split across buffers; must outlive the link
UdpPacketInterface(UDPComponent *udp_component, uint8_t *tx_buffer) : parent_(udp_component), tx_buffer_(tx_buffer) {}
/// @param tx_buffer Joins packets split across buffers, sized by code generation to max_packet_size; must outlive
/// the link. A larger max_packet_size set later is limited to it for those packets.
UdpPacketInterface(UDPComponent *udp_component, std::span<uint8_t> tx_buffer)
: parent_(udp_component), tx_buffer_(tx_buffer) {}
void setup() override;
bool send_to_interface(const packet_interface::PacketBuffer &data,
@@ -30,7 +32,7 @@ class UdpPacketInterface : public packet_interface::PacketInterface {
void receive_(std::span<const uint8_t> data);
UDPComponent *parent_;
uint8_t *const tx_buffer_;
const std::span<uint8_t> tx_buffer_;
};
} // namespace esphome::udp
#endif
@@ -71,6 +71,16 @@ TEST_F(UdpPacketInterfaceTest, OversizedPacketNotSent) {
EXPECT_FALSE(this->link_.send_to_interface(PacketBuffer(&header, 1, &body, nullptr, 0), {}));
}
TEST_F(UdpPacketInterfaceTest, SplitPacketLimitedToBuffer) {
this->link_.setup();
// Raised above the copy buffer after code generation sized it
this->link_.set_max_packet_size(100);
uint8_t header = 0;
Packet body_data{1, 2, 3, 4, 5, 6, 7, 8};
PacketBuffer body(body_data);
EXPECT_FALSE(this->link_.send_to_interface(PacketBuffer(&header, 1, &body, nullptr, 0), {}));
}
} // namespace esphome::udp::testing
#endif