mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2025-08-04 21:44:38 +08:00
Fixed bug #46467: ip_frag() shouldn't modify pbuf in case of a retransmission
This commit is contained in:
parent
697be5c2c3
commit
576f49ee2b
@ -690,11 +690,10 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
|
|||||||
#endif
|
#endif
|
||||||
struct ip_hdr *original_iphdr;
|
struct ip_hdr *original_iphdr;
|
||||||
struct ip_hdr *iphdr;
|
struct ip_hdr *iphdr;
|
||||||
u16_t nfb;
|
const u16_t nfb = (netif->mtu - IP_HLEN) / 8;
|
||||||
u16_t left, cop;
|
u16_t left, fragsize;
|
||||||
u16_t mtu = netif->mtu;
|
u16_t ofo;
|
||||||
u16_t ofo, omf;
|
int last;
|
||||||
u16_t last;
|
|
||||||
u16_t poff = IP_HLEN;
|
u16_t poff = IP_HLEN;
|
||||||
u16_t tmp;
|
u16_t tmp;
|
||||||
#if !LWIP_NETIF_TX_SINGLE_PBUF
|
#if !LWIP_NETIF_TX_SINGLE_PBUF
|
||||||
@ -704,36 +703,27 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
|
|||||||
|
|
||||||
original_iphdr = (struct ip_hdr *)p->payload;
|
original_iphdr = (struct ip_hdr *)p->payload;
|
||||||
iphdr = original_iphdr;
|
iphdr = original_iphdr;
|
||||||
|
LWIP_ERROR("ip4_frag() does not support IP options", IPH_HL(iphdr) * 4 == IP_HLEN, return ERR_VAL);
|
||||||
|
|
||||||
/* Save original offset */
|
/* Save original offset */
|
||||||
tmp = lwip_ntohs(IPH_OFFSET(iphdr));
|
tmp = ntohs(IPH_OFFSET(iphdr));
|
||||||
ofo = tmp & IP_OFFMASK;
|
ofo = tmp & IP_OFFMASK;
|
||||||
omf = tmp & IP_MF;
|
LWIP_ERROR("ip_frag(): MF already set", (tmp & IP_MF) == 0, return ERR_VAL);
|
||||||
|
|
||||||
left = p->tot_len - IP_HLEN;
|
left = p->tot_len - IP_HLEN;
|
||||||
|
|
||||||
nfb = (mtu - IP_HLEN) / 8;
|
|
||||||
|
|
||||||
while (left) {
|
while (left) {
|
||||||
last = (left <= mtu - IP_HLEN);
|
|
||||||
|
|
||||||
/* Set new offset and MF flag */
|
|
||||||
tmp = omf | (IP_OFFMASK & (ofo));
|
|
||||||
if (!last) {
|
|
||||||
tmp = tmp | IP_MF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fill this fragment */
|
/* Fill this fragment */
|
||||||
cop = last ? left : nfb * 8;
|
fragsize = (left < nfb * 8) ? left : nfb * 8;
|
||||||
|
|
||||||
#if LWIP_NETIF_TX_SINGLE_PBUF
|
#if LWIP_NETIF_TX_SINGLE_PBUF
|
||||||
rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
|
rambuf = pbuf_alloc(PBUF_IP, fragsize, PBUF_RAM);
|
||||||
if (rambuf == NULL) {
|
if (rambuf == NULL) {
|
||||||
goto memerr;
|
goto memerr;
|
||||||
}
|
}
|
||||||
LWIP_ASSERT("this needs a pbuf in one piece!",
|
LWIP_ASSERT("this needs a pbuf in one piece!",
|
||||||
(rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
|
(rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
|
||||||
poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
|
poff += pbuf_copy_partial(p, rambuf->payload, fragsize, poff);
|
||||||
/* make room for the IP header */
|
/* make room for the IP header */
|
||||||
if (pbuf_header(rambuf, IP_HLEN)) {
|
if (pbuf_header(rambuf, IP_HLEN)) {
|
||||||
pbuf_free(rambuf);
|
pbuf_free(rambuf);
|
||||||
@ -757,16 +747,14 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
|
|||||||
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
|
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
|
||||||
iphdr = (struct ip_hdr *)rambuf->payload;
|
iphdr = (struct ip_hdr *)rambuf->payload;
|
||||||
|
|
||||||
/* Can just adjust p directly for needed offset. */
|
left_to_copy = fragsize;
|
||||||
p->payload = (u8_t *)p->payload + poff;
|
|
||||||
p->len -= poff;
|
|
||||||
|
|
||||||
left_to_copy = cop;
|
|
||||||
while (left_to_copy) {
|
while (left_to_copy) {
|
||||||
struct pbuf_custom_ref *pcr;
|
struct pbuf_custom_ref *pcr;
|
||||||
newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
|
u16_t plen = p->len - poff;
|
||||||
|
newpbuflen = (left_to_copy < plen) ? left_to_copy : plen;
|
||||||
/* Is this pbuf already empty? */
|
/* Is this pbuf already empty? */
|
||||||
if (!newpbuflen) {
|
if (!newpbuflen) {
|
||||||
|
poff = 0;
|
||||||
p = p->next;
|
p = p->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -776,7 +764,8 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
|
|||||||
goto memerr;
|
goto memerr;
|
||||||
}
|
}
|
||||||
/* Mirror this pbuf, although we might not need all of it. */
|
/* Mirror this pbuf, although we might not need all of it. */
|
||||||
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
|
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc,
|
||||||
|
(u8_t*)p->payload + poff, newpbuflen);
|
||||||
if (newpbuf == NULL) {
|
if (newpbuf == NULL) {
|
||||||
ip_frag_free_pbuf_custom_ref(pcr);
|
ip_frag_free_pbuf_custom_ref(pcr);
|
||||||
pbuf_free(rambuf);
|
pbuf_free(rambuf);
|
||||||
@ -792,6 +781,7 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
|
|||||||
pbuf_cat(rambuf, newpbuf);
|
pbuf_cat(rambuf, newpbuf);
|
||||||
left_to_copy -= newpbuflen;
|
left_to_copy -= newpbuflen;
|
||||||
if (left_to_copy) {
|
if (left_to_copy) {
|
||||||
|
poff = 0;
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -799,8 +789,15 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
|
|||||||
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
|
||||||
|
|
||||||
/* Correct header */
|
/* Correct header */
|
||||||
|
last = (left <= netif->mtu - IP_HLEN);
|
||||||
|
|
||||||
|
/* Set new offset and MF flag */
|
||||||
|
tmp = (IP_OFFMASK & (ofo));
|
||||||
|
if (!last) {
|
||||||
|
tmp = tmp | IP_MF;
|
||||||
|
}
|
||||||
IPH_OFFSET_SET(iphdr, lwip_htons(tmp));
|
IPH_OFFSET_SET(iphdr, lwip_htons(tmp));
|
||||||
IPH_LEN_SET(iphdr, lwip_htons(cop + IP_HLEN));
|
IPH_LEN_SET(iphdr, lwip_htons(fragsize + IP_HLEN));
|
||||||
IPH_CHKSUM_SET(iphdr, 0);
|
IPH_CHKSUM_SET(iphdr, 0);
|
||||||
#if CHECKSUM_GEN_IP
|
#if CHECKSUM_GEN_IP
|
||||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) {
|
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) {
|
||||||
@ -822,7 +819,7 @@ ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pbuf_free(rambuf);
|
pbuf_free(rambuf);
|
||||||
left -= cop;
|
left -= fragsize;
|
||||||
ofo += nfb;
|
ofo += nfb;
|
||||||
}
|
}
|
||||||
MIB2_STATS_INC(mib2.ipfragoks);
|
MIB2_STATS_INC(mib2.ipfragoks);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user