Skip to content

Commit e6decac

Browse files
szekelyiszd-a-vdevyte
authored
Fix/enable UDP packet reassembly (#7036)
* Fix/enable UDP packet reassembly UdpContext didn't care about pbuf chaining when receiving datagrams, leading to fragments delivered to the application as individual packets. * Provide pbuf_get_contiguous for backwards compatibility with LwIP 1.4 Implementation copied verbatim from LwIP 2.1.2 * Cosmetic changes to meet coding style Co-authored-by: david gauchard <[email protected]> Co-authored-by: Develo <[email protected]>
1 parent cd56dc0 commit e6decac

File tree

1 file changed

+106
-12
lines changed

1 file changed

+106
-12
lines changed

libraries/ESP8266WiFi/src/include/UdpContext.h

+106-12
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ class UdpContext
187187
if (!_rx_buf)
188188
return 0;
189189

190-
return _rx_buf->len - _rx_buf_offset;
190+
return _rx_buf->tot_len - _rx_buf_offset;
191191
}
192192

193193
size_t tell() const
@@ -202,7 +202,7 @@ class UdpContext
202202
}
203203

204204
bool isValidOffset(const size_t pos) const {
205-
return (pos <= _rx_buf->len);
205+
return (pos <= _rx_buf->tot_len);
206206
}
207207

208208
CONST IPAddress& getRemoteAddress() CONST
@@ -238,6 +238,10 @@ class UdpContext
238238
}
239239

240240
auto deleteme = _rx_buf;
241+
242+
while(_rx_buf->len != _rx_buf->tot_len)
243+
_rx_buf = _rx_buf->next;
244+
241245
_rx_buf = _rx_buf->next;
242246

243247
if (_rx_buf)
@@ -274,10 +278,10 @@ class UdpContext
274278

275279
int read()
276280
{
277-
if (!_rx_buf || _rx_buf_offset >= _rx_buf->len)
281+
if (!_rx_buf || _rx_buf_offset >= _rx_buf->tot_len)
278282
return -1;
279283

280-
char c = reinterpret_cast<char*>(_rx_buf->payload)[_rx_buf_offset];
284+
char c = pbuf_get_at(_rx_buf, _rx_buf_offset);
281285
_consume(1);
282286
return c;
283287
}
@@ -287,22 +291,28 @@ class UdpContext
287291
if (!_rx_buf)
288292
return 0;
289293

290-
size_t max_size = _rx_buf->len - _rx_buf_offset;
294+
size_t max_size = _rx_buf->tot_len - _rx_buf_offset;
291295
size = (size < max_size) ? size : max_size;
292-
DEBUGV(":urd %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf_offset);
296+
DEBUGV(":urd %d, %d, %d\r\n", size, _rx_buf->tot_len, _rx_buf_offset);
297+
298+
void* buf = pbuf_get_contiguous(_rx_buf, dst, size, size, _rx_buf_offset);
299+
if(!buf)
300+
return 0;
301+
302+
if(buf != dst)
303+
memcpy(dst, buf, size);
293304

294-
memcpy(dst, reinterpret_cast<char*>(_rx_buf->payload) + _rx_buf_offset, size);
295305
_consume(size);
296306

297307
return size;
298308
}
299309

300310
int peek() const
301311
{
302-
if (!_rx_buf || _rx_buf_offset == _rx_buf->len)
312+
if (!_rx_buf || _rx_buf_offset == _rx_buf->tot_len)
303313
return -1;
304314

305-
return reinterpret_cast<char*>(_rx_buf->payload)[_rx_buf_offset];
315+
return pbuf_get_at(_rx_buf, _rx_buf_offset);
306316
}
307317

308318
void flush()
@@ -311,7 +321,7 @@ class UdpContext
311321
if (!_rx_buf)
312322
return;
313323

314-
_consume(_rx_buf->len - _rx_buf_offset);
324+
_consume(_rx_buf->tot_len - _rx_buf_offset);
315325
}
316326

317327
size_t append(const char* data, size_t size)
@@ -432,8 +442,8 @@ class UdpContext
432442
void _consume(size_t size)
433443
{
434444
_rx_buf_offset += size;
435-
if (_rx_buf_offset > _rx_buf->len) {
436-
_rx_buf_offset = _rx_buf->len;
445+
if (_rx_buf_offset > _rx_buf->tot_len) {
446+
_rx_buf_offset = _rx_buf->tot_len;
437447
}
438448
}
439449

@@ -522,6 +532,90 @@ class UdpContext
522532
reinterpret_cast<UdpContext*>(arg)->_recv(upcb, p, srcaddr, srcport);
523533
}
524534

535+
#if LWIP_VERSION_MAJOR == 1
536+
/*
537+
* Code in this conditional block is copied/backported verbatim from
538+
* LwIP 2.1.2 to provide pbuf_get_contiguous.
539+
*/
540+
541+
static const struct pbuf *
542+
pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset)
543+
{
544+
u16_t offset_left = in_offset;
545+
const struct pbuf *pbuf_it = in;
546+
547+
/* get the correct pbuf */
548+
while ((pbuf_it != NULL) && (pbuf_it->len <= offset_left)) {
549+
offset_left = (u16_t)(offset_left - pbuf_it->len);
550+
pbuf_it = pbuf_it->next;
551+
}
552+
if (out_offset != NULL) {
553+
*out_offset = offset_left;
554+
}
555+
return pbuf_it;
556+
}
557+
558+
u16_t
559+
pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
560+
{
561+
const struct pbuf *p;
562+
u16_t left = 0;
563+
u16_t buf_copy_len;
564+
u16_t copied_total = 0;
565+
566+
LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
567+
LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
568+
569+
/* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
570+
for (p = buf; len != 0 && p != NULL; p = p->next) {
571+
if ((offset != 0) && (offset >= p->len)) {
572+
/* don't copy from this buffer -> on to the next */
573+
offset = (u16_t)(offset - p->len);
574+
} else {
575+
/* copy from this buffer. maybe only partially. */
576+
buf_copy_len = (u16_t)(p->len - offset);
577+
if (buf_copy_len > len) {
578+
buf_copy_len = len;
579+
}
580+
/* copy the necessary parts of the buffer */
581+
MEMCPY(&((char *)dataptr)[left], &((char *)p->payload)[offset], buf_copy_len);
582+
copied_total = (u16_t)(copied_total + buf_copy_len);
583+
left = (u16_t)(left + buf_copy_len);
584+
len = (u16_t)(len - buf_copy_len);
585+
offset = 0;
586+
}
587+
}
588+
return copied_total;
589+
}
590+
591+
void *
592+
pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset)
593+
{
594+
const struct pbuf *q;
595+
u16_t out_offset;
596+
597+
LWIP_ERROR("pbuf_get_contiguous: invalid buf", (p != NULL), return NULL;);
598+
LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (buffer != NULL), return NULL;);
599+
LWIP_ERROR("pbuf_get_contiguous: invalid dataptr", (bufsize >= len), return NULL;);
600+
601+
q = pbuf_skip_const(p, offset, &out_offset);
602+
if (q != NULL) {
603+
if (q->len >= (out_offset + len)) {
604+
/* all data in this pbuf, return zero-copy */
605+
return (u8_t *)q->payload + out_offset;
606+
}
607+
/* need to copy */
608+
if (pbuf_copy_partial(q, buffer, len, out_offset) != len) {
609+
/* copying failed: pbuf is too short */
610+
return NULL;
611+
}
612+
return buffer;
613+
}
614+
/* pbuf is too short (offset does not fit in) */
615+
return NULL;
616+
}
617+
#endif
618+
525619
private:
526620
udp_pcb* _pcb;
527621
pbuf* _rx_buf;

0 commit comments

Comments
 (0)