mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-02-22 12:39:55 +00:00
task #6849: Calculate checksum when creating TCP segments, not when (re-)transmitting them.
This commit is contained in:
parent
84ed9de21a
commit
f83ace2034
@ -13,6 +13,10 @@ HISTORY
|
|||||||
|
|
||||||
++ New features:
|
++ New features:
|
||||||
|
|
||||||
|
2010-03-14: Simon Goldschmidt
|
||||||
|
* tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum
|
||||||
|
when creating TCP segments, not when (re-)transmitting them.
|
||||||
|
|
||||||
2010-03-07: Simon Goldschmidt
|
2010-03-07: Simon Goldschmidt
|
||||||
* sockets.c: bug #28775 (select/event_callback: only check select_cb_list
|
* sockets.c: bug #28775 (select/event_callback: only check select_cb_list
|
||||||
on change) plus use SYS_LIGHTWEIGHT_PROT to protect the select code.
|
on change) plus use SYS_LIGHTWEIGHT_PROT to protect the select code.
|
||||||
|
@ -55,6 +55,25 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Define some copy-macros for checksum-on-copy so that the code looks
|
||||||
|
nicer by preventing too many ifdef's. */
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
#define TCP_DATA_COPY(dst, src, len, seg) do { \
|
||||||
|
tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \
|
||||||
|
len, &seg->chksum, &seg->chksum_swapped); \
|
||||||
|
seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0)
|
||||||
|
#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \
|
||||||
|
tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped);
|
||||||
|
#else /* TCP_CHECKSUM_ON_COPY*/
|
||||||
|
#define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len)
|
||||||
|
#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len)
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY*/
|
||||||
|
|
||||||
|
/** Define this to 1 for an extra check that the output checksum is valid
|
||||||
|
* (usefule when the checksum is generated by the application, not the stack) */
|
||||||
|
#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK
|
||||||
|
#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Forward declarations.*/
|
/* Forward declarations.*/
|
||||||
static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
|
static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
|
||||||
@ -152,6 +171,13 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
|
|||||||
#if TCP_OVERSIZE_DBGCHECK
|
#if TCP_OVERSIZE_DBGCHECK
|
||||||
seg->oversize_left = 0;
|
seg->oversize_left = 0;
|
||||||
#endif /* TCP_OVERSIZE_DBGCHECK */
|
#endif /* TCP_OVERSIZE_DBGCHECK */
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
seg->chksum = 0;
|
||||||
|
seg->chksum_swapped = 0;
|
||||||
|
/* check optflags */
|
||||||
|
LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED",
|
||||||
|
(optflags & TF_SEG_DATA_CHECKSUMMED) == 0);
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
|
|
||||||
/* build TCP header */
|
/* build TCP header */
|
||||||
if (pbuf_header(p, TCP_HLEN)) {
|
if (pbuf_header(p, TCP_HLEN)) {
|
||||||
@ -229,6 +255,24 @@ tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,
|
|||||||
#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM)
|
#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM)
|
||||||
#endif /* TCP_OVERSIZE */
|
#endif /* TCP_OVERSIZE */
|
||||||
|
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
/** Add a checksum of newly added data to the segment */
|
||||||
|
static void
|
||||||
|
tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum,
|
||||||
|
u8_t *seg_chksum_swapped)
|
||||||
|
{
|
||||||
|
u32_t helper;
|
||||||
|
/* add chksum to old chksum and fold to u16_t */
|
||||||
|
helper = chksum + *seg_chksum;
|
||||||
|
chksum = FOLD_U32T(helper);
|
||||||
|
if ((len & 1) != 0) {
|
||||||
|
*seg_chksum_swapped = 1 - *seg_chksum_swapped;
|
||||||
|
chksum = SWAP_BYTES_IN_WORD(chksum);
|
||||||
|
}
|
||||||
|
*seg_chksum = chksum;
|
||||||
|
}
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write data for sending (but does not send it immediately).
|
* Write data for sending (but does not send it immediately).
|
||||||
*
|
*
|
||||||
@ -258,6 +302,11 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
|||||||
u16_t oversize = 0;
|
u16_t oversize = 0;
|
||||||
u16_t oversize_used = 0;
|
u16_t oversize_used = 0;
|
||||||
#endif /* TCP_OVERSIZE */
|
#endif /* TCP_OVERSIZE */
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
u16_t concat_chksum = 0;
|
||||||
|
u8_t concat_chksum_swapped = 0;
|
||||||
|
u16_t concat_chksummed = 0;
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
|
|
||||||
#if LWIP_NETIF_TX_SINGLE_PBUF
|
#if LWIP_NETIF_TX_SINGLE_PBUF
|
||||||
/* Always copy to try to create single pbufs for TX */
|
/* Always copy to try to create single pbufs for TX */
|
||||||
@ -405,7 +454,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
|||||||
#if TCP_OVERSIZE_DBGCHECK
|
#if TCP_OVERSIZE_DBGCHECK
|
||||||
last_unsent->oversize_left = oversize;
|
last_unsent->oversize_left = oversize;
|
||||||
#endif /* TCP_OVERSIZE_DBGCHECK */
|
#endif /* TCP_OVERSIZE_DBGCHECK */
|
||||||
MEMCPY(concat_p->payload, (u8_t*)arg + pos, seglen);
|
TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
concat_chksummed += seglen;
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
} else {
|
} else {
|
||||||
/* Data is not copied */
|
/* Data is not copied */
|
||||||
if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
|
if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
|
||||||
@ -413,6 +465,12 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
|||||||
("tcp_write: could not allocate memory for zero-copy pbuf\n"));
|
("tcp_write: could not allocate memory for zero-copy pbuf\n"));
|
||||||
goto memerr;
|
goto memerr;
|
||||||
}
|
}
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
/* calculate the checksum of nocopy-data */
|
||||||
|
tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen,
|
||||||
|
&concat_chksum, &concat_chksum_swapped);
|
||||||
|
concat_chksummed += seglen;
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
/* reference the non-volatile payload data */
|
/* reference the non-volatile payload data */
|
||||||
concat_p->payload = (u8_t*)arg + pos;
|
concat_p->payload = (u8_t*)arg + pos;
|
||||||
}
|
}
|
||||||
@ -438,6 +496,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
|||||||
u16_t left = len - pos;
|
u16_t left = len - pos;
|
||||||
u16_t max_len = pcb->mss - optlen;
|
u16_t max_len = pcb->mss - optlen;
|
||||||
u16_t seglen = left > max_len ? max_len : left;
|
u16_t seglen = left > max_len ? max_len : left;
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
u16_t chksum = 0;
|
||||||
|
u8_t chksum_swapped = 0;
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
|
|
||||||
if (apiflags & TCP_WRITE_FLAG_COPY) {
|
if (apiflags & TCP_WRITE_FLAG_COPY) {
|
||||||
/* If copy is set, memory should be allocated and data copied
|
/* If copy is set, memory should be allocated and data copied
|
||||||
@ -448,7 +510,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
|||||||
}
|
}
|
||||||
LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen",
|
LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen",
|
||||||
(p->len >= seglen));
|
(p->len >= seglen));
|
||||||
MEMCPY((char *)p->payload + optlen, (u8_t*)arg + pos, seglen);
|
TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped);
|
||||||
} else {
|
} else {
|
||||||
/* Copy is not set: First allocate a pbuf for holding the data.
|
/* Copy is not set: First allocate a pbuf for holding the data.
|
||||||
* Since the referenced data is available at least until it is
|
* Since the referenced data is available at least until it is
|
||||||
@ -463,6 +525,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
|||||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
|
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
|
||||||
goto memerr;
|
goto memerr;
|
||||||
}
|
}
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
/* calculate the checksum of nocopy-data */
|
||||||
|
chksum = ~inet_chksum((u8_t*)arg + pos, seglen);
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
/* reference the non-volatile payload data */
|
/* reference the non-volatile payload data */
|
||||||
p2->payload = (u8_t*)arg + pos;
|
p2->payload = (u8_t*)arg + pos;
|
||||||
|
|
||||||
@ -495,6 +561,11 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
|||||||
#if TCP_OVERSIZE_DBGCHECK
|
#if TCP_OVERSIZE_DBGCHECK
|
||||||
seg->oversize_left = oversize;
|
seg->oversize_left = oversize;
|
||||||
#endif /* TCP_OVERSIZE_DBGCHECK */
|
#endif /* TCP_OVERSIZE_DBGCHECK */
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
seg->chksum = chksum;
|
||||||
|
seg->chksum_swapped = chksum_swapped;
|
||||||
|
seg->flags |= TF_SEG_DATA_CHECKSUMMED;
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
/* Fix dataptr for the nocopy case */
|
/* Fix dataptr for the nocopy case */
|
||||||
if ((apiflags & TCP_WRITE_FLAG_COPY) == 0) {
|
if ((apiflags & TCP_WRITE_FLAG_COPY) == 0) {
|
||||||
seg->dataptr = (u8_t*)arg + pos;
|
seg->dataptr = (u8_t*)arg + pos;
|
||||||
@ -534,7 +605,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
|||||||
for (p = last_unsent->p; p; p = p->next) {
|
for (p = last_unsent->p; p; p = p->next) {
|
||||||
p->tot_len += oversize_used;
|
p->tot_len += oversize_used;
|
||||||
if (p->next == NULL) {
|
if (p->next == NULL) {
|
||||||
MEMCPY((u8_t *)p->payload + p->len, arg, oversize_used);
|
TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent);
|
||||||
p->len += oversize_used;
|
p->len += oversize_used;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -554,6 +625,13 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
|
|||||||
(last_unsent != NULL));
|
(last_unsent != NULL));
|
||||||
pbuf_cat(last_unsent->p, concat_p);
|
pbuf_cat(last_unsent->p, concat_p);
|
||||||
last_unsent->len += concat_p->tot_len;
|
last_unsent->len += concat_p->tot_len;
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
if (concat_chksummed) {
|
||||||
|
tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
|
||||||
|
&last_unsent->chksum_swapped);
|
||||||
|
last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
|
||||||
|
}
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1013,11 +1091,45 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
|||||||
|
|
||||||
seg->tcphdr->chksum = 0;
|
seg->tcphdr->chksum = 0;
|
||||||
#if CHECKSUM_GEN_TCP
|
#if CHECKSUM_GEN_TCP
|
||||||
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
&(pcb->local_ip),
|
{
|
||||||
|
u32_t acc;
|
||||||
|
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
|
||||||
|
u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
|
||||||
|
&(pcb->remote_ip),
|
||||||
|
IP_PROTO_TCP, seg->p->tot_len);
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
|
||||||
|
if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
|
||||||
|
LWIP_ASSERT("data included but not checksummed",
|
||||||
|
seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rebuild TCP header checksum (TCP header changes for retransmissions!) */
|
||||||
|
acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
|
||||||
&(pcb->remote_ip),
|
&(pcb->remote_ip),
|
||||||
IP_PROTO_TCP, seg->p->tot_len);
|
IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
|
||||||
#endif
|
/* add payload checksum */
|
||||||
|
if (seg->chksum_swapped) {
|
||||||
|
seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
|
||||||
|
seg->chksum_swapped = 0;
|
||||||
|
}
|
||||||
|
acc += (u16_t)~(seg->chksum);
|
||||||
|
seg->tcphdr->chksum = FOLD_U32T(acc);
|
||||||
|
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
|
||||||
|
if (chksum_slow != seg->tcphdr->chksum) {
|
||||||
|
LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
|
||||||
|
("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",
|
||||||
|
seg->tcphdr->chksum, chksum_slow));
|
||||||
|
seg->tcphdr->chksum = chksum_slow;
|
||||||
|
}
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
|
||||||
|
}
|
||||||
|
#else /* TCP_CHECKSUM_ON_COPY */
|
||||||
|
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
|
||||||
|
&(pcb->remote_ip),
|
||||||
|
IP_PROTO_TCP, seg->p->tot_len);
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
|
#endif /* CHECKSUM_GEN_TCP */
|
||||||
TCP_STATS_INC(tcp.xmit);
|
TCP_STATS_INC(tcp.xmit);
|
||||||
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
|
@ -253,12 +253,16 @@ PACK_STRUCT_END
|
|||||||
|
|
||||||
#endif /* LWIP_EVENT_API */
|
#endif /* LWIP_EVENT_API */
|
||||||
|
|
||||||
|
/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */
|
||||||
#if TCP_OVERSIZE && defined(LWIP_DEBUG)
|
#if TCP_OVERSIZE && defined(LWIP_DEBUG)
|
||||||
#define TCP_OVERSIZE_DBGCHECK 1
|
#define TCP_OVERSIZE_DBGCHECK 1
|
||||||
#else
|
#else
|
||||||
#define TCP_OVERSIZE_DBGCHECK 0
|
#define TCP_OVERSIZE_DBGCHECK 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Don't generate chceksum on copy if CHECKSUM_GEN_TCP is disabled */
|
||||||
|
#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP)
|
||||||
|
|
||||||
/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */
|
/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */
|
||||||
struct tcp_seg {
|
struct tcp_seg {
|
||||||
struct tcp_seg *next; /* used when putting segements on a queue */
|
struct tcp_seg *next; /* used when putting segements on a queue */
|
||||||
@ -270,9 +274,15 @@ struct tcp_seg {
|
|||||||
pbuf in unsent (used for asserting vs.
|
pbuf in unsent (used for asserting vs.
|
||||||
tcp_pcb.unsent_oversized only) */
|
tcp_pcb.unsent_oversized only) */
|
||||||
#endif /* TCP_OVERSIZE_DBGCHECK */
|
#endif /* TCP_OVERSIZE_DBGCHECK */
|
||||||
|
#if TCP_CHECKSUM_ON_COPY
|
||||||
|
u16_t chksum;
|
||||||
|
u8_t chksum_swapped;
|
||||||
|
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||||
u8_t flags;
|
u8_t flags;
|
||||||
#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */
|
#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */
|
||||||
#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */
|
#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */
|
||||||
|
#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is
|
||||||
|
checksummed into 'chksum' */
|
||||||
struct tcp_hdr *tcphdr; /* the TCP header */
|
struct tcp_hdr *tcphdr; /* the TCP header */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user