diff --git a/CHANGELOG b/CHANGELOG index e7228c31..3188dc5a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,11 @@ HISTORY ++ New features: + 2010-04-30: Simon Goldschmidt + * udp.h/.c, pbuf.h/.c: task #6849: added udp_send(_to/_if) functions that + take a precalculated checksum, added pbuf_fill_chksum() to copy data + into a pbuf and at the same time calculating the checksum for that data + 2010-04-29: Simon Goldschmidt * ip_addr.h, etharp.h/.c, autoip.c: Create overridable macros for copying 2-byte-aligned IP addresses and MAC addresses diff --git a/src/core/pbuf.c b/src/core/pbuf.c index fe4b049b..ffe354d2 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -73,6 +73,9 @@ #if TCP_QUEUE_OOSEQ #include "lwip/tcp_impl.h" #endif +#if LWIP_CHECKSUM_ON_COPY +#include "lwip/inet_chksum.h" +#endif #include @@ -927,3 +930,44 @@ pbuf_coalesce(struct pbuf *p, pbuf_layer layer) pbuf_free(p); return q; } + +#if LWIP_CHECKSUM_ON_COPY +/** + * Copies data into a single pbuf (*not* into a pbuf queue!) and updates + * the checksum while copying + * + * @param p the pbuf to copy data into + * @param start_offset offset of p->payload where to copy the data to + * @param dataptr data to copy into the pbuf + * @param len length of data to copy into the pbuf + * @param chksum pointer to the checksum which is updated + * @return ERR_OK if successful, another error if the data does not fit + * within the (first) pbuf (no pbuf queues!) + */ +err_t +pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum) +{ + u32_t acc; + u16_t copy_chksum; + char *dst_ptr; + LWIP_ASSERT("p != NULL", p != NULL); + LWIP_ASSERT("dataptr != NULL", dataptr != NULL); + LWIP_ASSERT("chksum != NULL", chksum != NULL); + LWIP_ASSERT("len != 0", len != 0); + + if ((start_offset >= p->len) || (start_offset + len > p->len)) { + return ERR_ARG; + } + + dst_ptr = ((char*)p->payload) + start_offset; + copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); + if ((start_offset & 1) != 0) { + copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); + } + acc = *chksum; + acc += copy_chksum; + *chksum = FOLD_U32T(acc); + return ERR_OK; +} +#endif /* LWIP_CHECKSUM_ON_COPY */ diff --git a/src/core/udp.c b/src/core/udp.c index 2ccf0d68..dbb12db6 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -336,6 +336,19 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); } +#if LWIP_CHECKSUM_ON_COPY +/** Same as udp_send() but with checksum + */ +err_t +udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum) +{ + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, + have_chksum, chksum); +} +#endif /* LWIP_CHECKSUM_ON_COPY */ + /** * Send data to a specified address using UDP. * @@ -357,6 +370,16 @@ err_t udp_sendto(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port) { +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); +} + +/** Same as udp_sendto(), but with checksum */ +err_t +udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, + u16_t dst_port, u8_t have_chksum, u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY */ struct netif *netif; LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); @@ -375,7 +398,11 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p, UDP_STATS_INC(udp.rterr); return ERR_RTE; } +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); +#else /* LWIP_CHECKSUM_ON_COPY */ return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); +#endif /* LWIP_CHECKSUM_ON_COPY */ } /** @@ -401,6 +428,17 @@ err_t udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) { +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); +} + +/** Same as udp_sendto_if(), but with checksum */ +err_t +udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, + u16_t dst_port, struct netif *netif, u8_t have_chksum, + u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY */ struct udp_hdr *udphdr; ip_addr_t *src_ip; err_t err; @@ -501,7 +539,18 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, /* calculate checksum */ #if CHECKSUM_GEN_UDP udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, - IP_PROTO_UDPLITE, q->tot_len, chklen); + IP_PROTO_UDPLITE, q->tot_len, +#if !LWIP_CHECKSUM_ON_COPY + chklen); +#else /* !LWIP_CHECKSUM_ON_COPY */ + (have_chksum ? UDP_HLEN : chklen)); + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } +#endif /* !LWIP_CHECKSUM_ON_COPY */ + /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udphdr->chksum == 0x0000) { udphdr->chksum = 0xffff; @@ -524,11 +573,25 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, /* calculate checksum */ #if CHECKSUM_GEN_UDP if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { - udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udphdr->chksum == 0x0000) { - udphdr->chksum = 0xffff; + u16_t udpchksum; +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP, + q->tot_len, UDP_HLEN); + acc = udpchksum + (u16_t)~(chksum); + udpchksum = FOLD_U32T(acc); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); } + + /* chksum zero must become 0xffff, as zero means 'no checksum' */ + if (udpchksum == 0x0000) { + udpchksum = 0xffff; + } + udphdr->chksum = udpchksum; } #endif /* CHECKSUM_GEN_UDP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index 9b4c024a..9ab75afd 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -111,6 +111,10 @@ err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from); u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset); err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer); +#if LWIP_CHECKSUM_ON_COPY +err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum); +#endif /* LWIP_CHECKSUM_ON_COPY */ #ifdef __cplusplus } diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index fd3b9d4f..ac1bb769 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -135,6 +135,18 @@ err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port); err_t udp_send (struct udp_pcb *pcb, struct pbuf *p); +#if LWIP_CHECKSUM_ON_COPY +err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, u8_t have_chksum, + u16_t chksum); +err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + u8_t have_chksum, u16_t chksum); +err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum); +#endif /* LWIP_CHECKSUM_ON_COPY */ + #define udp_flags(pcb) ((pcb)->flags) #define udp_setflags(pcb, f) ((pcb)->flags = (f))