- if(pbuf_header(p, -(hdrlen * 4))){
- /* drop short packets */
- LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
- TCP_STATS_INC(tcp.lenerr);
- goto dropped;
+ tcphdr_opt1len = (hdrlen * 4) - TCP_HLEN;
+ tcphdr_opt2 = NULL;
+ if (p->len < hdrlen * 4) {
+ if (p->len >= TCP_HLEN) {
+ /* TCP header fits into first pbuf, options don't - data is in the next pbuf */
+ u16_t optlen = tcphdr_opt1len;
+ pbuf_header(p, -TCP_HLEN); /* cannot fail */
+ LWIP_ASSERT("tcphdr_opt1len >= p->len", tcphdr_opt1len >= p->len);
+ LWIP_ASSERT("p->next != NULL", p->next != NULL);
+ tcphdr_opt1len = p->len;
+ if (optlen > tcphdr_opt1len) {
+ s16_t opt2len;
+ /* options continue in the next pbuf: set p to zero length and hide the
+ options in the next pbuf (adjusting p->tot_len) */
+ u8_t phret = pbuf_header(p, -(s16_t)tcphdr_opt1len);
+ LWIP_ASSERT("phret == 0", phret == 0);
+ tcphdr_opt2 = (u8_t*)p->next->payload;
+ opt2len = optlen - tcphdr_opt1len;
+ phret = pbuf_header(p->next, -opt2len);
+ LWIP_ASSERT("phret == 0", phret == 0);
+ /* p->next->payload now points to the TCP data */
+ /* manually adjust p->tot_len to changed p->next->tot_len change */
+ p->tot_len -= opt2len;
+ }
+ LWIP_ASSERT("p->len == 0", p->len == 0);
+ } else {
+ /* drop short packets */
+ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
+ TCP_STATS_INC(tcp.lenerr);
+ goto dropped;
+ }
+ } else {
+ pbuf_header(p, -(hdrlen * 4)); /* cannot fail */